Skip to content

Commit f9a0cc8

Browse files
committed
Merge #23188
2 parents 8fce323 + a5e054d commit f9a0cc8

File tree

1 file changed

+106
-5
lines changed

1 file changed

+106
-5
lines changed

library/src/scala/Predef.scala

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ package scala
1515
import scala.language.implicitConversions
1616

1717
import scala.collection.{mutable, immutable, ArrayOps, StringOps}, immutable.WrappedString
18-
import scala.annotation.{elidable, implicitNotFound}, elidable.ASSERTION
18+
import scala.annotation.{elidable, implicitNotFound, publicInBinary, targetName, experimental}, elidable.ASSERTION
1919
import scala.annotation.meta.{ companionClass, companionMethod }
20+
import scala.annotation.internal.RuntimeChecked
2021

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

140+
/**
141+
* Retrieve the single value of a type with a unique inhabitant.
142+
*
143+
* @example {{{
144+
* object Foo
145+
* val foo = valueOf[Foo.type]
146+
* // foo is Foo.type = Foo
147+
*
148+
* val bar = valueOf[23]
149+
* // bar is 23.type = 23
150+
* }}}
151+
* @group utilities
152+
*/
153+
inline def valueOf[T]: T = compiletime.summonFrom {
154+
case ev: ValueOf[T] => ev.value
155+
}
156+
157+
139158
/** The `String` type in Scala has all the methods of the underlying
140159
* [[java.lang.String]], of which it is just an alias.
141160
*
@@ -217,6 +236,13 @@ object Predef extends LowPriorityImplicits {
217236
*/
218237
@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`
219238

239+
/** Summon a given value of type `T`. Usually, the argument is not passed explicitly.
240+
*
241+
* @tparam T the type of the value to be summoned
242+
* @return the given value typed: the provided type parameter
243+
*/
244+
transparent inline def summon[T](using x: T): x.type = x
245+
220246
/** Used to mark code blocks as being expressions, instead of being taken as part of anonymous classes and the like.
221247
* This is just a different name for [[identity]].
222248
*
@@ -248,7 +274,9 @@ object Predef extends LowPriorityImplicits {
248274
*/
249275
@inline def locally[T](@deprecatedName("x") x: T): T = x
250276

251-
// assertions ---------------------------------------------------------
277+
// ==============================================================================================
278+
// ========================================= ASSERTIONS =========================================
279+
// ==============================================================================================
252280

253281
/** Tests an expression, throwing an `AssertionError` if false.
254282
* Calls to this method will not be generated if `-Xelide-below`
@@ -259,7 +287,8 @@ object Predef extends LowPriorityImplicits {
259287
* @group assertions
260288
*/
261289
@elidable(ASSERTION)
262-
def assert(assertion: Boolean): Unit = {
290+
@targetName("assert") @publicInBinary
291+
protected def oldAssert(assertion: Boolean): Unit = {
263292
if (!assertion)
264293
throw new java.lang.AssertionError("assertion failed")
265294
}
@@ -274,11 +303,22 @@ object Predef extends LowPriorityImplicits {
274303
* @group assertions
275304
*/
276305
@elidable(ASSERTION) @inline
277-
final def assert(assertion: Boolean, message: => Any): Unit = {
306+
@targetName("assert") @publicInBinary
307+
protected def oldAssert(assertion: Boolean, message: => Any): Unit = {
278308
if (!assertion)
279309
throw new java.lang.AssertionError("assertion failed: "+ message)
280310
}
281311

312+
transparent inline def assert(inline assertion: Boolean, inline message: => Any): Unit =
313+
if !assertion then scala.runtime.Scala3RunTime.assertFailed(message)
314+
315+
transparent inline def assert(inline assertion: Boolean): Unit =
316+
if !assertion then scala.runtime.Scala3RunTime.assertFailed()
317+
318+
// ==============================================================================================
319+
// ========================================= ASSUMPTIONS ========================================
320+
// ==============================================================================================
321+
282322
/** Tests an expression, throwing an `AssertionError` if false.
283323
* This method differs from assert only in the intent expressed:
284324
* assert contains a predicate which needs to be proven, while
@@ -370,7 +410,7 @@ object Predef extends LowPriorityImplicits {
370410
@inline def formatted(fmtstr: String): String = fmtstr format self
371411
}
372412

373-
/** Injects String concatenation operator `+` to any classes.
413+
/** Injects String concatenation operator `+` to any classes.
374414
* @group implicit-classes-any
375415
*/
376416
@(deprecated @companionMethod)("Implicit injection of + is deprecated. Convert to String to call +", "2.13.0")
@@ -508,6 +548,67 @@ object Predef extends LowPriorityImplicits {
508548
*/
509549
// $ to avoid accidental shadowing (e.g. scala/bug#7788)
510550
implicit def $conforms[A]: A => A = <:<.refl
551+
552+
// Extension methods for working with explicit nulls
553+
554+
/** Strips away the nullability from a value. Note that `.nn` performs a checked cast,
555+
* so if invoked on a `null` value it will throw an `NullPointerException`.
556+
* @example {{{
557+
* val s1: String | Null = "hello"
558+
* val s2: String = s1.nn
559+
*
560+
* val s3: String | Null = null
561+
* val s4: String = s3.nn // throw NullPointerException
562+
* }}}
563+
*/
564+
extension [T](x: T | Null) inline def nn: x.type & T =
565+
if x.asInstanceOf[Any] == null then scala.runtime.Scala3RunTime.nnFail()
566+
x.asInstanceOf[x.type & T]
567+
568+
extension (inline x: AnyRef | Null)
569+
/** Enables an expression of type `T|Null`, where `T` is a subtype of `AnyRef`, to be checked for `null`
570+
* using `eq` rather than only `==`. This is needed because `Null` no longer has
571+
* `eq` or `ne` methods, only `==` and `!=` inherited from `Any`. */
572+
inline def eq(inline y: AnyRef | Null): Boolean =
573+
x.asInstanceOf[AnyRef] eq y.asInstanceOf[AnyRef]
574+
/** Enables an expression of type `T|Null`, where `T` is a subtype of `AnyRef`, to be checked for `null`
575+
* using `ne` rather than only `!=`. This is needed because `Null` no longer has
576+
* `eq` or `ne` methods, only `==` and `!=` inherited from `Any`. */
577+
inline def ne(inline y: AnyRef | Null): Boolean =
578+
!(x eq y)
579+
580+
extension (opt: Option.type)
581+
@experimental
582+
inline def fromNullable[T](t: T | Null): Option[T] = Option(t).asInstanceOf[Option[T]]
583+
584+
/** A type supporting Self-based type classes.
585+
*
586+
* A is TC
587+
*
588+
* expands to
589+
*
590+
* TC { type Self = A }
591+
*
592+
* which is what is needed for a context bound `[A: TC]`.
593+
*/
594+
@experimental
595+
infix type is[A <: AnyKind, B <: Any{type Self <: AnyKind}] = B { type Self = A }
596+
597+
extension [T](x: T)
598+
/**Asserts that a term should be exempt from static checks that can be reliably checked at runtime.
599+
* @example {{{
600+
* val xs: Option[Int] = Option(1)
601+
* xs.runtimeChecked match
602+
* case Some(x) => x // `Some(_)` can be checked at runtime, so no warning
603+
* }}}
604+
* @example {{{
605+
* val xs: List[Int] = List(1,2,3)
606+
* val y :: ys = xs.runtimeChecked // `_ :: _` can be checked at runtime, so no warning
607+
* }}}
608+
*/
609+
@experimental
610+
inline def runtimeChecked: x.type @RuntimeChecked = x: @RuntimeChecked
611+
511612
}
512613

513614
/** The `LowPriorityImplicits` class provides implicit values that

0 commit comments

Comments
 (0)