All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.scalajs.js.Union.scala Maven / Gradle / Ivy

There is a newer version: 1.0.0-M3
Show newest version
/*                     __                                               *\
**     ________ ___   / /  ___      __ ____  Scala.js API               **
**    / __/ __// _ | / /  / _ | __ / // __/  (c) 2013-2015, LAMP/EPFL   **
**  __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \    http://scala-lang.org/     **
** /____/\___/_/ |_/____/_/ | |__/ /____/                               **
**                          |/____/                                     **
\*                                                                      */


package scala.scalajs.js

import scala.language.implicitConversions

/** Value of type A or B (union type).
 *
 *  Scala does not have union types, but they are important to many
 *  interoperability scenarios. This type provides a (partial) encoding of
 *  union types using implicit evidences.
 */
sealed trait |[A, B] // scalastyle:ignore

object | { // scalastyle:ignore
  /** Evidence that `A <: B`, taking top-level `|`-types into account. */
  sealed trait Evidence[-A, +B]

  /** A unique (and typically dead-code-eliminated away) instance of
   *  `Evidence`.
   */
  private object ReusableEvidence extends Evidence[scala.Any, scala.Any]

  abstract sealed class EvidenceLowestPrioImplicits {
    /** If `A <: B2`, then `A <: B1 | B2`. */
    implicit def right[A, B1, B2](implicit ev: Evidence[A, B2]): Evidence[A, B1 | B2] =
      ReusableEvidence.asInstanceOf[Evidence[A, B1 | B2]]
  }

  abstract sealed class EvidenceLowPrioImplicits extends EvidenceLowestPrioImplicits {
    /** `Int <: Double`, because that's true in Scala.js. */
    implicit def intDouble: Evidence[Int, Double] =
      ReusableEvidence.asInstanceOf[Evidence[Int, Double]]

    /** If `A <: B1`, then `A <: B1 | B2`. */
    implicit def left[A, B1, B2](implicit ev: Evidence[A, B1]): Evidence[A, B1 | B2] =
      ReusableEvidence.asInstanceOf[Evidence[A, B1 | B2]]

    /** If `A <: B`, then `A <: js.UndefOr[B]`. */
    implicit def undefOr[A, B](implicit ev: Evidence[A, B]): Evidence[A, UndefOr[B]] =
      ReusableEvidence.asInstanceOf[Evidence[A, UndefOr[B]]]
  }

  object Evidence extends EvidenceLowPrioImplicits {
    /** `A <: A`. */
    implicit def base[A]: Evidence[A, A] =
      ReusableEvidence.asInstanceOf[Evidence[A, A]]

    /** If `A1 <: B` and `A2 <: B`, then `A1 | A2 <: B`. */
    implicit def allSubtypes[A1, A2, B](
        implicit ev1: Evidence[A1, B], ev2: Evidence[A2, B]): Evidence[A1 | A2, B] =
      ReusableEvidence.asInstanceOf[Evidence[A1 | A2, B]]
  }

  /** Upcast `A` to `B1 | B2`.
   *
   *  This needs evidence that `A <: B1 | B2`.
   */
  implicit def from[A, B1, B2](a: A)(implicit ev: Evidence[A, B1 | B2]): B1 | B2 =
    a.asInstanceOf[B1 | B2]

  /** Operations on union types. */
  implicit class UnionOps[A <: _ | _](val self: A) extends AnyVal {
    /** Explicitly merge a union type to a supertype (which might not be a
     *  union type itself).
     *
     *  This needs evidence that `A <: B`.
     */
    def merge[B](implicit ev: |.Evidence[A, B]): B =
      self.asInstanceOf[B]
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy