Skip to content
Open
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
27 changes: 27 additions & 0 deletions library/src/scala/Console.scala
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,35 @@ object Console extends AnsiColor {
private val inVar = new DynamicVariable[BufferedReader](
new BufferedReader(new InputStreamReader(java.lang.System.in)))

/** Sets the default output stream for the current thread by changing the
* current binding directly, discarding the previously bound stream. Unlike
* `withOut`, this method does not itself restore the previous stream; note,
* however, that if it is called inside a `withOut` body, that enclosing
* scope will restore its own saved stream when it exits.
*
* @param out the new output stream to install as the default for the
* current thread
*/
protected def setOutDirect(out: PrintStream): Unit = outVar.value = out
/** Sets the default error stream for the current thread by changing the
* current binding directly, discarding the previously bound stream. Unlike
* `withErr`, this method does not itself restore the previous stream; note,
* however, that if it is called inside a `withErr` body, that enclosing
* scope will restore its own saved stream when it exits.
*
* @param err the new error stream to install as the default for the
* current thread
*/
protected def setErrDirect(err: PrintStream): Unit = errVar.value = err
/** Sets the default input reader for the current thread by changing the
* current binding directly, discarding the previously bound reader. Unlike
* `withIn`, this method does not itself restore the previous reader; note,
* however, that if it is called inside a `withIn` body, that enclosing
* scope will restore its own saved reader when it exits.
*
* @param in the new input reader to install as the default for the
* current thread
*/
protected def setInDirect(in: BufferedReader): Unit = inVar.value = in

/** The default output, can be overridden by `withOut`.
Expand Down
1 change: 1 addition & 0 deletions library/src/scala/Conversion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ object Conversion:

/** Unwraps an `into`. */
extension [T](x: into[T])
/** Returns `x` viewed at its underlying type `T`, revealing the opaque `into[T]` alias. */
def underlying: T = x
end Conversion
8 changes: 8 additions & 0 deletions library/src/scala/DelayedInit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,13 @@ import scala.language.`2.13`
*/
@deprecated("DelayedInit semantics can be surprising. Support for `App` will continue. See the release notes for more details: https://github.com/scala/scala/releases/tag/v2.11.0", "2.11.0")
trait DelayedInit {
/** Receives the rewritten initialization code of an inheriting class or object.
*
* Implementations decide whether, when, and how often to evaluate `x`, and may
* run other code before or after it.
*
* @param x the initialization code, passed by name so it is not evaluated until
* the implementation forces it
*/
def delayedInit(x: => Unit): Unit
}
142 changes: 139 additions & 3 deletions library/src/scala/Enumeration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,22 @@ import scala.util.matching.Regex
* ```
*
* @param initial The initial value from which to count the integers that
* identifies values at run-time.
* identify values at run-time.
*/
@SerialVersionUID(8476000850333817230L)
abstract class Enumeration (initial: Int) extends Serializable {
thisenum =>

/** Creates an enumeration whose values are identified by integers counting from zero. */
def this() = this(0)

/* Note that `readResolve` cannot be private, since otherwise
the JVM does not invoke it when deserializing subclasses. */
/** Returns the instance held in this enumeration class's Scala module field, so that
* deserializing an enumeration defined as an `object` yields that singleton rather
* than a copy. The runtime class is assumed to be a module class; deserializing a
* subclass that is not an `object` fails, since no such field exists.
*/
protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)

/** The name of this enumeration. */
Expand Down Expand Up @@ -137,8 +143,8 @@ abstract class Enumeration (initial: Int) extends Serializable {
private def nextNameOrNull: String | Null =
if (nextName != null && nextName.hasNext) nextName.next() else null

/** The highest integer amongst those used to identify values in this
* enumeration.
/** The one higher than the highest integer amongst those used to identify
* values in this enumeration, or `initial` if it has no values yet.
*/
private var topId = initial

Expand Down Expand Up @@ -238,14 +244,25 @@ abstract class Enumeration (initial: Int) extends Serializable {
/** A marker so we can tell whose values belong to whom come reflective-naming time. */
private[Enumeration] val outerEnum = thisenum

/** Compares this value with `that` by their ids.
*
* @param that the value to compare with
* @return `-1` if this value's id is less than `that`'s, `0` if the ids are equal, `1` otherwise
*/
override def compare(that: Value): Int =
if (this.id < that.id) -1
else if (this.id == that.id) 0
else 1
/** Tests whether `other` is a value of the same enumeration instance with the same id.
*
* @param other the object to compare with
* @return `true` if `other` is a `Value` belonging to this same enumeration and has an equal id, `false` otherwise
*/
override def equals(other: Any): Boolean = other match {
case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
case _ => false
}
/** Returns a hash code derived from this value's id. */
override def hashCode(): Int = id.##

/** Creates a ValueSet which contains this value and another one.
Expand All @@ -261,8 +278,25 @@ abstract class Enumeration (initial: Int) extends Serializable {
*/
@SerialVersionUID(0 - 3501153230598116017L)
protected class Val(i: Int, name: String | Null) extends Value with Serializable {
/** Creates a value identified by the integer `i`, taking its name from the
* enumeration's `nextName` iterator if that iterator has a next element.
*
* @param i an integer that identifies this value at run-time; it must be unique amongst all values of the enumeration
*/
def this(i: Int) = this(i, nextNameOrNull)
/** Creates a value called `name`, identified by the enumeration's current `nextId`.
* That id must still be unused: constructing values with explicit ids can leave
* `nextId` pointing at an id already taken, in which case this constructor fails
* the duplicate-id assertion.
*
* @param name a human-readable name for this value, or `null` to have the name determined reflectively
*/
def this(name: String | Null) = this(nextId, name)
/** Creates a value identified by the enumeration's current `nextId`, taking its
* name from the enumeration's `nextName` iterator if that iterator has a next
* element. As with the other constructors, the id must still be unused, or the
* duplicate-id assertion fails.
*/
def this() = this(nextId)

assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
Expand All @@ -271,12 +305,21 @@ abstract class Enumeration (initial: Int) extends Serializable {
nextId = i + 1
if (nextId > topId) topId = nextId
if (i < bottomId) bottomId = i
/** Returns the integer that identifies this value at run-time. */
def id: Int = i
/** Returns the name of this value. If no explicit name was given, the name is
* determined reflectively from the fields of the enclosing enumeration, or a
* placeholder string is returned if no such field exists.
*/
override def toString(): String =
if (name != null) name
else try thisenum.nameOf(i)
catch { case _: NoSuchElementException => "<Invalid enum: no field for #" + i + ">" }

/** Returns the value of the deserialized enumeration singleton whose id matches
* this value's id, so that deserialized values are identical to the enumeration's
* own values, or this value itself if that enumeration has no value mapping yet.
*/
protected def readResolve(): AnyRef = {
val enumeration = thisenum.readResolve().asInstanceOf[Enumeration]
if (enumeration.vmap == null) this
Expand All @@ -286,12 +329,27 @@ abstract class Enumeration (initial: Int) extends Serializable {

/** An ordering by id for values of this set. */
implicit object ValueOrdering extends Ordering[Value] {
/** Compares two values of this enumeration by their ids.
*
* @param x the first value to compare
* @param y the second value to compare
* @return `-1` if `x`'s id is less than `y`'s, `0` if the ids are equal, `1` otherwise
*/
def compare(x: Value, y: Value): Int = x compare y
}

/** A class for sets of values.
* Iterating through this set will yield values in increasing order of their ids.
*
* Ids are stored adjusted by the lowest id in use by the enclosing enumeration at
* the time each operation runs, so the behavior described for the methods below
* holds only as long as that lowest id does not change. Creating a value whose id
* is lower than every id created so far shifts the adjustment and thereby
* reinterprets the ids already stored in existing sets, so that a set built before
* the shift can afterwards report membership of, and iterate over, different values
* than it was built from. As stated for the enumeration itself, values should not be
* added after its construction.
*
* @param nnIds The set of ids of values (adjusted so that the lowest value does
* not fall below zero), organized as a `BitSet`.
* @define Coll `collection.immutable.SortedSet`
Expand All @@ -304,37 +362,110 @@ abstract class Enumeration (initial: Int) extends Serializable {
with StrictOptimizedIterableOps[Value, immutable.Set, ValueSet]
with Serializable {

/** Returns the ordering of this set, which orders values by increasing id. */
implicit def ordering: Ordering[Value] = ValueOrdering
/** Creates a set restricted to the values of this set that lie in the given range.
*
* @param from the lowest value to retain, or `None` to start at the lowest value of this set
* @param until the lowest value to drop, or `None` to retain values up to the highest value of this set
* @return a new `ValueSet` holding the values of this set within the given range
*/
def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))

/** Returns the empty value set of this enumeration. */
override def empty: ValueSet = ValueSet.empty
/** Returns the number of values in this set, which is always known. */
override def knownSize: Int = nnIds.size
/** Tests whether this set contains no values. */
override def isEmpty: Boolean = nnIds.isEmpty
/** Tests whether this set contains the given value.
*
* @param v the value to test
* @return `true` if `v` is an element of this set, `false` otherwise
*/
def contains(v: Value): Boolean = nnIds contains (v.id - bottomId)
/** Creates a set containing all values of this set and the given value.
*
* @param value the value to include
* @return a new `ValueSet`, holding the same values as this set if `value` is
* already an element of it
*/
def incl (value: Value): ValueSet = new ValueSet(nnIds + (value.id - bottomId))
/** Creates a set containing all values of this set except the given value.
*
* @param value the value to exclude
* @return a new `ValueSet`, holding the same values as this set if `value` is
* not an element of it
*/
def excl (value: Value): ValueSet = new ValueSet(nnIds - (value.id - bottomId))
/** Returns an iterator over the values of this set in increasing order of their ids. */
def iterator: Iterator[Value] = nnIds.iterator map (id => thisenum.apply(bottomId + id))
override def iteratorFrom(start: Value): Iterator[Value] = nnIds iteratorFrom start.id map (id => thisenum.apply(bottomId + id))
/** Returns the name used for this set in its string representation, of the form `Enum.ValueSet`. */
override def className: String = s"$thisenum.ValueSet"
/** Creates a bit mask for the zero-adjusted ids in this set as a
* new array of longs
*/
def toBitMask: Array[Long] = nnIds.toBitMask

/** Creates a value set holding the values of the given collection.
*
* @param coll the values to include
* @return a new `ValueSet` containing the values of `coll`
*/
override protected def fromSpecific(coll: IterableOnce[Value]): ValueSet = ValueSet.fromSpecific(coll)
/** Returns a builder for value sets of this enumeration. */
override protected def newSpecificBuilder = ValueSet.newBuilder

/** Creates a value set by applying `f` to every value of this set.
*
* @param f the function to apply to each value
* @return a new `ValueSet` holding the results of applying `f`, with duplicates collapsed
*/
def map(f: Value => Value): ValueSet = fromSpecific(new View.Map(this, f))
/** Creates a value set by applying `f` to every value of this set and concatenating the results.
*
* @param f the function to apply to each value
* @return a new `ValueSet` holding all values produced by `f`, with duplicates collapsed
*/
def flatMap(f: Value => IterableOnce[Value]): ValueSet = fromSpecific(new View.FlatMap(this, f))

// necessary for disambiguation:
/** Creates a sorted set by applying `f` to every value of this set.
*
* @tparam B the element type of the resulting set
* @param f the function to apply to each value
* @param ev the ordering by which the resulting set is sorted
* @return a new sorted set holding the results of applying `f`, with duplicates collapsed
*/
override def map[B](f: Value => B)(implicit @implicitNotFound(ValueSet.ordMsg) ev: Ordering[B]): immutable.SortedSet[B] =
super[SortedSet].map[B](f)
/** Creates a sorted set by applying `f` to every value of this set and concatenating the results.
*
* @tparam B the element type of the resulting set
* @param f the function to apply to each value
* @param ev the ordering by which the resulting set is sorted
* @return a new sorted set holding all elements produced by `f`, with duplicates collapsed
*/
override def flatMap[B](f: Value => IterableOnce[B])(implicit @implicitNotFound(ValueSet.ordMsg) ev: Ordering[B]): immutable.SortedSet[B] =
super[SortedSet].flatMap[B](f)
/** Creates a sorted set of pairs formed from the values of this set and the elements of `that`.
*
* @tparam B the element type of `that`
* @param that the collection to zip with this set
* @param ev the ordering by which the resulting set of pairs is sorted
* @return a new sorted set of pairs, holding as many pairs as the shorter of this set and `that`
*/
override def zip[B](that: IterableOnce[B])(implicit @implicitNotFound(ValueSet.zipOrdMsg) ev: Ordering[(Value, B)]): immutable.SortedSet[(Value, B)] =
super[SortedSet].zip[B](that)
/** Creates a sorted set by applying `pf` to every value of this set for which it is defined.
*
* @tparam B the element type of the resulting set
* @param pf the partial function to apply to each value
* @param ev the ordering by which the resulting set is sorted
* @return a new sorted set holding the results of applying `pf`, with duplicates collapsed
*/
override def collect[B](pf: PartialFunction[Value, B])(implicit @implicitNotFound(ValueSet.ordMsg) ev: Ordering[B]): immutable.SortedSet[B] =
super[SortedSet].collect[B](pf)

Expand Down Expand Up @@ -362,6 +493,11 @@ abstract class Enumeration (initial: Int) extends Serializable {
def clear() = b.clear()
def result() = new ValueSet(b.toImmutable)
}
/** Creates a value set holding the values of the given collection.
*
* @param it the values to include
* @return a new `ValueSet` containing the values of `it`
*/
def fromSpecific(it: IterableOnce[Value]): ValueSet =
newBuilder.addAll(it).result()
}
Expand Down
7 changes: 7 additions & 0 deletions library/src/scala/MatchError.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,12 @@ final class MatchError(@transient obj: Any) extends RuntimeException {
this
}

/** Returns a detail message describing the object that failed to match any pattern.
* The message is the object's `toString` representation followed by its class name
* in parentheses, as in `5 (of class java.lang.Integer)`. If the object is `null`,
* the message is just `"null"`; if invoking `toString` on it throws, the message
* omits the representation and is `"an instance of class "` followed by the class
* name.
*/
override def getMessage(): String = objString
}
32 changes: 32 additions & 0 deletions library/src/scala/NamedTuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,27 @@ object NamedTuple:
=> (@unused eqV: CanEqual[V1, V2])
=> CanEqual[NamedTuple[N1, V1], NamedTuple[N2, V2]] = CanEqual.derived

/** Creates a named tuple with the names `N` and the element values of the tuple `x`.
*
* @tparam N the tuple of name types labelling the elements; for named tuples written
* in source code these are literal string types, but the signature only
* requires a tuple
* @tparam V the tuple of element value types
* @param x the tuple holding the element values
* @return the named tuple that pairs the names `N` with the element values of `x`
*/
def apply[N <: Tuple, V <: Tuple](x: V): NamedTuple[N, V] = x

/** Decomposes a named tuple into its element values, so that a pattern match on a
* named tuple binds the values without their names. The match always succeeds.
*
* @tparam N the tuple of name types labelling the elements; for named tuples written
* in source code these are literal string types, but the signature only
* requires a tuple
* @tparam V the tuple of element value types
* @param x the named tuple to decompose
* @return `Some` wrapping the underlying tuple of element values of `x`
*/
def unapply[N <: Tuple, V <: Tuple](x: NamedTuple[N, V]): Some[V] = Some(x)

/** A named tuple expression will desugar to a call to `build`. For instance,
Expand Down Expand Up @@ -251,6 +270,19 @@ object NamedTupleDecomposition:

@publicInBinary
private[NamedTupleDecomposition]
/** Creates a map from field names to element values, preserving the order of the fields.
*
* If the two tuples have different sizes, the extra elements of the larger tuple will
* be disregarded.
*
* @tparam N the tuple of field name types; this is not checked, but callers must pass
* only string names, because the result is cast to a map with `String` keys
* @tparam V the tuple of element value types
* @param names the field names, in field order
* @param values the element values, in the same order as `names`
* @return a [[scala.collection.immutable.SeqMap]] that maps each name to the value at
* the same position
*/
def createSeqMap[N <: Tuple, V <: Tuple](names: N, values: V): SeqMap[String, Tuple.Union[V]] =
SeqMap.newBuilder
.addAll(names.productIterator.zip(values.productIterator))
Expand Down
1 change: 1 addition & 0 deletions library/src/scala/NotImplementedError.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ import scala.language.`2.13`
* @param msg the error message describing which implementation is missing
*/
final class NotImplementedError(msg: String) extends Error(msg) {
/** Creates a `NotImplementedError` with the default message `"an implementation is missing"`. */
def this() = this("an implementation is missing")
}
Loading
Loading