Skip to content

chore: port definitions to Predef #23188

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

Closed
wants to merge 1 commit into from
Closed
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
111 changes: 106 additions & 5 deletions library/src/scala/Predef.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ package scala
import scala.language.implicitConversions

import scala.collection.{mutable, immutable, ArrayOps, StringOps}, immutable.WrappedString
import scala.annotation.{elidable, implicitNotFound}, elidable.ASSERTION
import scala.annotation.{elidable, implicitNotFound, publicInBinary, targetName, experimental}, elidable.ASSERTION
import scala.annotation.meta.{ companionClass, companionMethod }
import scala.annotation.internal.RuntimeChecked

/** The `Predef` object provides definitions that are accessible in all Scala
* compilation units without explicit qualification.
Expand Down Expand Up @@ -136,6 +137,24 @@ object Predef extends LowPriorityImplicits {
*/
@inline def valueOf[T](implicit vt: ValueOf[T]): T = vt.value

/**
* Retrieve the single value of a type with a unique inhabitant.
*
* @example {{{
* object Foo
* val foo = valueOf[Foo.type]
* // foo is Foo.type = Foo
*
* val bar = valueOf[23]
* // bar is 23.type = 23
* }}}
* @group utilities
*/
inline def valueOf[T]: T = compiletime.summonFrom {
case ev: ValueOf[T] => ev.value
}


/** The `String` type in Scala has all the methods of the underlying
* [[java.lang.String]], of which it is just an alias.
*
Expand Down Expand Up @@ -217,6 +236,13 @@ object Predef extends LowPriorityImplicits {
*/
@inline def implicitly[T](implicit e: T): T = e // TODO: when dependent method types are on by default, give this result type `e.type`, so that inliner has better chance of knowing which method to inline in calls like `implicitly[MatchingStrategy[Option]].zero`

/** Summon a given value of type `T`. Usually, the argument is not passed explicitly.
*
* @tparam T the type of the value to be summoned
* @return the given value typed: the provided type parameter
*/
transparent inline def summon[T](using x: T): x.type = x

/** Used to mark code blocks as being expressions, instead of being taken as part of anonymous classes and the like.
* This is just a different name for [[identity]].
*
Expand Down Expand Up @@ -248,7 +274,9 @@ object Predef extends LowPriorityImplicits {
*/
@inline def locally[T](@deprecatedName("x") x: T): T = x

// assertions ---------------------------------------------------------
// ==============================================================================================
// ========================================= ASSERTIONS =========================================
// ==============================================================================================

/** Tests an expression, throwing an `AssertionError` if false.
* Calls to this method will not be generated if `-Xelide-below`
Expand All @@ -259,7 +287,8 @@ object Predef extends LowPriorityImplicits {
* @group assertions
*/
@elidable(ASSERTION)
def assert(assertion: Boolean): Unit = {
@targetName("assert") @publicInBinary
protected def oldAssert(assertion: Boolean): Unit = {
if (!assertion)
throw new java.lang.AssertionError("assertion failed")
}
Expand All @@ -274,11 +303,22 @@ object Predef extends LowPriorityImplicits {
* @group assertions
*/
@elidable(ASSERTION) @inline
final def assert(assertion: Boolean, message: => Any): Unit = {
@targetName("assert") @publicInBinary
protected def oldAssert(assertion: Boolean, message: => Any): Unit = {
if (!assertion)
throw new java.lang.AssertionError("assertion failed: "+ message)
}

transparent inline def assert(inline assertion: Boolean, inline message: => Any): Unit =
if !assertion then scala.runtime.Scala3RunTime.assertFailed(message)

transparent inline def assert(inline assertion: Boolean): Unit =
if !assertion then scala.runtime.Scala3RunTime.assertFailed()

// ==============================================================================================
// ========================================= ASSUMPTIONS ========================================
// ==============================================================================================

/** Tests an expression, throwing an `AssertionError` if false.
* This method differs from assert only in the intent expressed:
* assert contains a predicate which needs to be proven, while
Expand Down Expand Up @@ -370,7 +410,7 @@ object Predef extends LowPriorityImplicits {
@inline def formatted(fmtstr: String): String = fmtstr format self
}

/** Injects String concatenation operator `+` to any classes.
/** Injects String concatenation operator `+` to any classes.
* @group implicit-classes-any
*/
@(deprecated @companionMethod)("Implicit injection of + is deprecated. Convert to String to call +", "2.13.0")
Expand Down Expand Up @@ -508,6 +548,67 @@ object Predef extends LowPriorityImplicits {
*/
// $ to avoid accidental shadowing (e.g. scala/bug#7788)
implicit def $conforms[A]: A => A = <:<.refl

// Extension methods for working with explicit nulls

/** Strips away the nullability from a value. Note that `.nn` performs a checked cast,
* so if invoked on a `null` value it will throw an `NullPointerException`.
* @example {{{
* val s1: String | Null = "hello"
* val s2: String = s1.nn
*
* val s3: String | Null = null
* val s4: String = s3.nn // throw NullPointerException
* }}}
*/
extension [T](x: T | Null) inline def nn: x.type & T =
if x.asInstanceOf[Any] == null then scala.runtime.Scala3RunTime.nnFail()
x.asInstanceOf[x.type & T]

extension (inline x: AnyRef | Null)
/** Enables an expression of type `T|Null`, where `T` is a subtype of `AnyRef`, to be checked for `null`
* using `eq` rather than only `==`. This is needed because `Null` no longer has
* `eq` or `ne` methods, only `==` and `!=` inherited from `Any`. */
inline def eq(inline y: AnyRef | Null): Boolean =
x.asInstanceOf[AnyRef] eq y.asInstanceOf[AnyRef]
/** Enables an expression of type `T|Null`, where `T` is a subtype of `AnyRef`, to be checked for `null`
* using `ne` rather than only `!=`. This is needed because `Null` no longer has
* `eq` or `ne` methods, only `==` and `!=` inherited from `Any`. */
inline def ne(inline y: AnyRef | Null): Boolean =
!(x eq y)

extension (opt: Option.type)
@experimental
inline def fromNullable[T](t: T | Null): Option[T] = Option(t).asInstanceOf[Option[T]]

/** A type supporting Self-based type classes.
*
* A is TC
*
* expands to
*
* TC { type Self = A }
*
* which is what is needed for a context bound `[A: TC]`.
*/
@experimental
infix type is[A <: AnyKind, B <: Any{type Self <: AnyKind}] = B { type Self = A }

extension [T](x: T)
/**Asserts that a term should be exempt from static checks that can be reliably checked at runtime.
* @example {{{
* val xs: Option[Int] = Option(1)
* xs.runtimeChecked match
* case Some(x) => x // `Some(_)` can be checked at runtime, so no warning
* }}}
* @example {{{
* val xs: List[Int] = List(1,2,3)
* val y :: ys = xs.runtimeChecked // `_ :: _` can be checked at runtime, so no warning
* }}}
*/
@experimental
inline def runtimeChecked: x.type @RuntimeChecked = x: @RuntimeChecked

}

/** The `LowPriorityImplicits` class provides implicit values that
Expand Down