Skip to content
This repository
file 149 lines (136 sloc) 7.459 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
package scala
package reflect

import java.lang.{ Class => jClass }
import scala.language.{implicitConversions, existentials}
import scala.runtime.ScalaRunTime.{ arrayClass, arrayElementClass }

/**
*
* A `ClassTag[T]` stores the erased class of a given type `T`, accessible via the `runtimeClass`
* field. This is particularly useful for instantiating `Array`s whose element types are unknown
* at compile time.
*
* `ClassTag`s are a weaker special case of [[scala.reflect.api.TypeTags#TypeTag]]s, in that they
* wrap only the runtime class of a given type, whereas a `TypeTag` contains all static type
* information. That is, `ClassTag`s are constructed from knowing only the top-level class of a
* type, without necessarily knowing all of its argument types. This runtime information is enough
* for runtime `Array` creation.
*
* For example:
* {{{
* scala> def mkArray[T : ClassTag](elems: T*) = Array[T](elems: _*)
* mkArray: [T](elems: T*)(implicit evidence$1: scala.reflect.ClassTag[T])Array[T]
*
* scala> mkArray(42, 13)
* res0: Array[Int] = Array(42, 13)
*
* scala> mkArray("Japan","Brazil","Germany")
* res1: Array[String] = Array(Japan, Brazil, Germany)
* }}}
*
* See [[scala.reflect.api.TypeTags]] for more examples, or the
* [[http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html Reflection Guide: TypeTags]]
* for more details.
*
*/
@scala.annotation.implicitNotFound(msg = "No ClassTag available for ${T}")
trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serializable {
  // please, don't add any APIs here, like it was with `newWrappedArray` and `newArrayBuilder`
  // class tags, and all tags in general, should be as minimalistic as possible

  /** A class representing the type `U` to which `T` would be erased.
* Note that there is no subtyping relationship between `T` and `U`.
*/
  def runtimeClass: jClass[_]

  /** Produces a `ClassTag` that knows how to instantiate an `Array[Array[T]]` */
  def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](arrayClass(runtimeClass))

  /** Produces a new array with element type `T` and length `len` */
  override def newArray(len: Int): Array[T] =
    runtimeClass match {
      case java.lang.Byte.TYPE => new Array[Byte](len).asInstanceOf[Array[T]]
      case java.lang.Short.TYPE => new Array[Short](len).asInstanceOf[Array[T]]
      case java.lang.Character.TYPE => new Array[Char](len).asInstanceOf[Array[T]]
      case java.lang.Integer.TYPE => new Array[Int](len).asInstanceOf[Array[T]]
      case java.lang.Long.TYPE => new Array[Long](len).asInstanceOf[Array[T]]
      case java.lang.Float.TYPE => new Array[Float](len).asInstanceOf[Array[T]]
      case java.lang.Double.TYPE => new Array[Double](len).asInstanceOf[Array[T]]
      case java.lang.Boolean.TYPE => new Array[Boolean](len).asInstanceOf[Array[T]]
      case java.lang.Void.TYPE => new Array[Unit](len).asInstanceOf[Array[T]]
      case _ => java.lang.reflect.Array.newInstance(runtimeClass, len).asInstanceOf[Array[T]]
    }

  /** A ClassTag[T] can serve as an extractor that matches only objects of type T.
*
* The compiler tries to turn unchecked type tests in pattern matches into checked ones
* by wrapping a `(_: T)` type pattern as `ct(_: T)`, where `ct` is the `ClassTag[T]` instance.
* Type tests necessary before calling other extractors are treated similarly.
* `SomeExtractor(...)` is turned into `ct(SomeExtractor(...))` if `T` in `SomeExtractor.unapply(x: T)`
* is uncheckable, but we have an instance of `ClassTag[T]`.
*/
  def unapply(x: Any): Option[T] = unapply_impl(x)
  def unapply(x: Byte): Option[T] = unapply_impl(x)
  def unapply(x: Short): Option[T] = unapply_impl(x)
  def unapply(x: Char): Option[T] = unapply_impl(x)
  def unapply(x: Int): Option[T] = unapply_impl(x)
  def unapply(x: Long): Option[T] = unapply_impl(x)
  def unapply(x: Float): Option[T] = unapply_impl(x)
  def unapply(x: Double): Option[T] = unapply_impl(x)
  def unapply(x: Boolean): Option[T] = unapply_impl(x)
  def unapply(x: Unit): Option[T] = unapply_impl(x)

  private def unapply_impl[U: ClassTag](x: U): Option[T] =
    if (x == null) None
    else {
      val staticClass = classTag[U].runtimeClass
      val dynamicClass = x.getClass
      val effectiveClass = if (staticClass.isPrimitive) staticClass else dynamicClass
      val conforms = runtimeClass.isAssignableFrom(effectiveClass)
      if (conforms) Some(x.asInstanceOf[T]) else None
    }

  // case class accessories
  override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]]
  override def equals(x: Any) = x.isInstanceOf[ClassTag[_]] && this.runtimeClass == x.asInstanceOf[ClassTag[_]].runtimeClass
  override def hashCode = scala.runtime.ScalaRunTime.hash(runtimeClass)
  override def toString = {
    def prettyprint(clazz: jClass[_]): String =
      if (clazz.isArray) s"Array[${prettyprint(arrayElementClass(clazz))}]" else
      clazz.getName
    prettyprint(runtimeClass)
  }
}

/**
* Class tags corresponding to primitive types and constructor/extractor for ClassTags.
*/
object ClassTag {
  private val ObjectTYPE = classOf[java.lang.Object]
  private val NothingTYPE = classOf[scala.runtime.Nothing$]
  private val NullTYPE = classOf[scala.runtime.Null$]

  val Byte : ClassTag[scala.Byte] = Manifest.Byte
  val Short : ClassTag[scala.Short] = Manifest.Short
  val Char : ClassTag[scala.Char] = Manifest.Char
  val Int : ClassTag[scala.Int] = Manifest.Int
  val Long : ClassTag[scala.Long] = Manifest.Long
  val Float : ClassTag[scala.Float] = Manifest.Float
  val Double : ClassTag[scala.Double] = Manifest.Double
  val Boolean : ClassTag[scala.Boolean] = Manifest.Boolean
  val Unit : ClassTag[scala.Unit] = Manifest.Unit
  val Any : ClassTag[scala.Any] = Manifest.Any
  val Object : ClassTag[java.lang.Object] = Manifest.Object
  val AnyVal : ClassTag[scala.AnyVal] = Manifest.AnyVal
  val AnyRef : ClassTag[scala.AnyRef] = Manifest.AnyRef
  val Nothing : ClassTag[scala.Nothing] = Manifest.Nothing
  val Null : ClassTag[scala.Null] = Manifest.Null

  def apply[T](runtimeClass1: jClass[_]): ClassTag[T] =
    runtimeClass1 match {
      case java.lang.Byte.TYPE => ClassTag.Byte.asInstanceOf[ClassTag[T]]
      case java.lang.Short.TYPE => ClassTag.Short.asInstanceOf[ClassTag[T]]
      case java.lang.Character.TYPE => ClassTag.Char.asInstanceOf[ClassTag[T]]
      case java.lang.Integer.TYPE => ClassTag.Int.asInstanceOf[ClassTag[T]]
      case java.lang.Long.TYPE => ClassTag.Long.asInstanceOf[ClassTag[T]]
      case java.lang.Float.TYPE => ClassTag.Float.asInstanceOf[ClassTag[T]]
      case java.lang.Double.TYPE => ClassTag.Double.asInstanceOf[ClassTag[T]]
      case java.lang.Boolean.TYPE => ClassTag.Boolean.asInstanceOf[ClassTag[T]]
      case java.lang.Void.TYPE => ClassTag.Unit.asInstanceOf[ClassTag[T]]
      case ObjectTYPE => ClassTag.Object.asInstanceOf[ClassTag[T]]
      case NothingTYPE => ClassTag.Nothing.asInstanceOf[ClassTag[T]]
      case NullTYPE => ClassTag.Null.asInstanceOf[ClassTag[T]]
      case _ => new ClassTag[T]{ def runtimeClass = runtimeClass1 }
    }

  def unapply[T](ctag: ClassTag[T]): Option[Class[_]] = Some(ctag.runtimeClass)
}
Something went wrong with that request. Please try again.