summaryrefslogtreecommitdiff
path: root/src/library/scala/reflect/ClassTags.scala
blob: 2833e7cc8ee626c4bcae3256255f99b27b21a72c (plain) (blame)
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
149
150
151
152
153
154
155
156
157
158
package scala.reflect

import java.lang.{ Class => jClass }
import scala.reflect.{ mirror => rm }

/** A `ClassTag[T]` wraps a Java class, which can be accessed via the `erasure` method.
 *  This is useful in itself, but also enables very important use case.
 *  Having this knowledge ClassTag can instantiate `Arrays`
 *  in those cases where the element type is unknown at compile time.
 *  Hence, ClassTag[T] conforms to the ArrayTag[T] trait.
 */
// 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
@annotation.implicitNotFound(msg = "No ClassTag available for ${T}")
abstract case class ClassTag[T](erasure: jClass[_]) extends ArrayTag[T] {
  // quick and dirty fix to a deadlock in Predef:
  // http://groups.google.com/group/scala-internals/browse_thread/thread/977de028a4e75d6f
  // todo. fix that in a sane way
  // assert(erasure != null)

  /** A Scala reflection type representing T.
   *  For ClassTags this representation is lossy (in their case tpe is retrospectively constructed from erasure).
   *  For TypeTags and GroundTypeTags the representation is almost precise, because it uses reification
   *  (information is lost only when T refers to non-locatable symbols, which are then reified as free variables). */
  def tpe: rm.Type = rm.classToType(erasure)

  /** A Scala reflection symbol representing T. */
  def symbol: rm.Symbol = rm.classToSymbol(erasure)

  /** Produces a `ClassTag` that knows how to build `Array[Array[T]]` */
  def wrap: ClassTag[Array[T]] = {
    val arrayClazz = java.lang.reflect.Array.newInstance(erasure, 0).getClass.asInstanceOf[jClass[Array[T]]]
    ClassTag[Array[T]](arrayClazz)
  }

  /** Produces a new array with element type `T` and length `len` */
  def newArray(len: Int): Array[T] =
    erasure 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(erasure, len).asInstanceOf[Array[T]]
    }
}

object ClassTag {
  private val ObjectTYPE = classOf[java.lang.Object]
  private val StringTYPE = classOf[java.lang.String]

  val Byte    : ClassTag[scala.Byte]       = new ClassTag[scala.Byte](java.lang.Byte.TYPE) { private def readResolve() = ClassTag.Byte }
  val Short   : ClassTag[scala.Short]      = new ClassTag[scala.Short](java.lang.Short.TYPE) { private def readResolve() = ClassTag.Short }
  val Char    : ClassTag[scala.Char]       = new ClassTag[scala.Char](java.lang.Character.TYPE) { private def readResolve() = ClassTag.Char }
  val Int     : ClassTag[scala.Int]        = new ClassTag[scala.Int](java.lang.Integer.TYPE) { private def readResolve() = ClassTag.Int }
  val Long    : ClassTag[scala.Long]       = new ClassTag[scala.Long](java.lang.Long.TYPE) { private def readResolve() = ClassTag.Long }
  val Float   : ClassTag[scala.Float]      = new ClassTag[scala.Float](java.lang.Float.TYPE) { private def readResolve() = ClassTag.Float }
  val Double  : ClassTag[scala.Double]     = new ClassTag[scala.Double](java.lang.Double.TYPE) { private def readResolve() = ClassTag.Double }
  val Boolean : ClassTag[scala.Boolean]    = new ClassTag[scala.Boolean](java.lang.Boolean.TYPE) { private def readResolve() = ClassTag.Boolean }
  val Unit    : ClassTag[scala.Unit]       = new ClassTag[scala.Unit](java.lang.Void.TYPE) { private def readResolve() = ClassTag.Unit }
  val Any     : ClassTag[scala.Any]        = new ClassTag[scala.Any](ObjectTYPE) { private def readResolve() = ClassTag.Any }
  val Object  : ClassTag[java.lang.Object] = new ClassTag[java.lang.Object](ObjectTYPE) { private def readResolve() = ClassTag.Object }
  val AnyVal  : ClassTag[scala.AnyVal]     = new ClassTag[scala.AnyVal](ObjectTYPE) { private def readResolve() = ClassTag.AnyVal }
  val AnyRef  : ClassTag[scala.AnyRef]     = new ClassTag[scala.AnyRef](ObjectTYPE) { private def readResolve() = ClassTag.AnyRef }
  val Nothing : ClassTag[scala.Nothing]    = new ClassTag[scala.Nothing](ObjectTYPE) { private def readResolve() = ClassTag.Nothing }
  val Null    : ClassTag[scala.Null]       = new ClassTag[scala.Null](ObjectTYPE) { private def readResolve() = ClassTag.Null }
  val String  : ClassTag[java.lang.String] = new ClassTag[java.lang.String](StringTYPE) { private def readResolve() = ClassTag.String }

  def apply[T](clazz: jClass[_]): ClassTag[T] =
    clazz 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 StringTYPE               => ClassTag.String.asInstanceOf[ClassTag[T]]
      case _                        => new ClassTag[T](clazz) {}
    }

  def apply[T](tpe: rm.Type): ClassTag[T] =
    tpe match {
      case rm.ByteTpe    => ClassTag.Byte.asInstanceOf[ClassTag[T]]
      case rm.ShortTpe   => ClassTag.Short.asInstanceOf[ClassTag[T]]
      case rm.CharTpe    => ClassTag.Char.asInstanceOf[ClassTag[T]]
      case rm.IntTpe     => ClassTag.Int.asInstanceOf[ClassTag[T]]
      case rm.LongTpe    => ClassTag.Long.asInstanceOf[ClassTag[T]]
      case rm.FloatTpe   => ClassTag.Float.asInstanceOf[ClassTag[T]]
      case rm.DoubleTpe  => ClassTag.Double.asInstanceOf[ClassTag[T]]
      case rm.BooleanTpe => ClassTag.Boolean.asInstanceOf[ClassTag[T]]
      case rm.UnitTpe    => ClassTag.Unit.asInstanceOf[ClassTag[T]]
      case rm.AnyTpe     => ClassTag.Any.asInstanceOf[ClassTag[T]]
      case rm.ObjectTpe  => ClassTag.Object.asInstanceOf[ClassTag[T]]
      case rm.AnyValTpe  => ClassTag.AnyVal.asInstanceOf[ClassTag[T]]
      case rm.AnyRefTpe  => ClassTag.AnyRef.asInstanceOf[ClassTag[T]]
      case rm.NothingTpe => ClassTag.Nothing.asInstanceOf[ClassTag[T]]
      case rm.NullTpe    => ClassTag.Null.asInstanceOf[ClassTag[T]]
      case rm.StringTpe  => ClassTag.String.asInstanceOf[ClassTag[T]]
      case _             => apply[T](rm.typeToClass(tpe.erasure))
    }

  implicit def toDeprecatedClassManifestApis[T](ctag: ClassTag[T]): DeprecatedClassManifestApis[T] = new DeprecatedClassManifestApis[T](ctag)
}

// this class should not be used directly in client code
class DeprecatedClassManifestApis[T](ctag: ClassTag[T]) {
  import scala.collection.mutable.{ WrappedArray, ArrayBuilder }

  @deprecated("Use `tpe` to analyze the underlying type", "2.10.0")
  def <:<(that: ClassManifest[_]): Boolean = ctag.tpe <:< that.tpe

  @deprecated("Use `tpe` to analyze the underlying type", "2.10.0")
  def >:>(that: ClassManifest[_]): Boolean = that <:< ctag

  @deprecated("Use `wrap` instead", "2.10.0")
  def arrayManifest: ClassManifest[Array[T]] = ctag.wrap

  @deprecated("Use a combination of `wrap` and `newArray` instead", "2.10.0")
  def newArray2(len: Int): Array[Array[T]] = ctag.wrap.newArray(len)

  @deprecated("Use a combination of `wrap` and `newArray` instead", "2.10.0")
  def newArray3(len: Int): Array[Array[Array[T]]] = ctag.wrap.wrap.newArray(len)

  @deprecated("Use a combination of `wrap` and `newArray` instead", "2.10.0")
  def newArray4(len: Int): Array[Array[Array[Array[T]]]] = ctag.wrap.wrap.wrap.newArray(len)

  @deprecated("Use a combination of `wrap` and `newArray` instead", "2.10.0")
  def newArray5(len: Int): Array[Array[Array[Array[Array[T]]]]] = ctag.wrap.wrap.wrap.wrap.newArray(len)

  @deprecated("Use `@scala.collection.mutable.WrappedArray` object instead", "2.10.0")
  def newWrappedArray(len: Int): WrappedArray[T] =
    ctag.erasure match {
      case java.lang.Byte.TYPE      => new WrappedArray.ofByte(new Array[Byte](len)).asInstanceOf[WrappedArray[T]]
      case java.lang.Short.TYPE     => new WrappedArray.ofShort(new Array[Short](len)).asInstanceOf[WrappedArray[T]]
      case java.lang.Character.TYPE => new WrappedArray.ofChar(new Array[Char](len)).asInstanceOf[WrappedArray[T]]
      case java.lang.Integer.TYPE   => new WrappedArray.ofInt(new Array[Int](len)).asInstanceOf[WrappedArray[T]]
      case java.lang.Long.TYPE      => new WrappedArray.ofLong(new Array[Long](len)).asInstanceOf[WrappedArray[T]]
      case java.lang.Float.TYPE     => new WrappedArray.ofFloat(new Array[Float](len)).asInstanceOf[WrappedArray[T]]
      case java.lang.Double.TYPE    => new WrappedArray.ofDouble(new Array[Double](len)).asInstanceOf[WrappedArray[T]]
      case java.lang.Boolean.TYPE   => new WrappedArray.ofBoolean(new Array[Boolean](len)).asInstanceOf[WrappedArray[T]]
      case java.lang.Void.TYPE      => new WrappedArray.ofUnit(new Array[Unit](len)).asInstanceOf[WrappedArray[T]]
      case _                        => new WrappedArray.ofRef[T with AnyRef](ctag.newArray(len).asInstanceOf[Array[T with AnyRef]]).asInstanceOf[WrappedArray[T]]
    }

  @deprecated("Use `@scala.collection.mutable.ArrayBuilder` object instead", "2.10.0")
  def newArrayBuilder(): ArrayBuilder[T] = ArrayBuilder.make[T]()(ctag)

  @deprecated("`typeArguments` is no longer supported, and will always return an empty list. Use `@scala.reflect.TypeTag` or `@scala.reflect.GroundTypeTag` to capture and analyze type arguments", "2.10.0")
  def typeArguments: List[OptManifest[_]] = List()
}