summaryrefslogtreecommitdiff
path: root/src/reflect/scala/reflect/api/TypeTags.scala
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-09-19 15:04:50 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-09-19 22:47:10 +0200
commit3fa900ca0ea244ac54df75dc2fd6d711739eface (patch)
treebd37a549da114d7030a7cbce14ecc527058dd1ad /src/reflect/scala/reflect/api/TypeTags.scala
parenteadf1d2080e0ce763e4c1920a26b80c8b8609ca0 (diff)
downloadscala-3fa900ca0ea244ac54df75dc2fd6d711739eface.tar.gz
scala-3fa900ca0ea244ac54df75dc2fd6d711739eface.tar.bz2
scala-3fa900ca0ea244ac54df75dc2fd6d711739eface.zip
SI-6363 removes scala.reflect.base
As the experience has shown, there's no need for a separate layer of reflection in scala-library.jar. Therefore I'm putting an end to it.
Diffstat (limited to 'src/reflect/scala/reflect/api/TypeTags.scala')
-rw-r--r--src/reflect/scala/reflect/api/TypeTags.scala354
1 files changed, 354 insertions, 0 deletions
diff --git a/src/reflect/scala/reflect/api/TypeTags.scala b/src/reflect/scala/reflect/api/TypeTags.scala
new file mode 100644
index 0000000000..a7e58d2bcb
--- /dev/null
+++ b/src/reflect/scala/reflect/api/TypeTags.scala
@@ -0,0 +1,354 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2012 LAMP/EPFL
+ * @author Martin Odersky
+ */
+
+package scala
+package reflect
+package api
+
+import java.lang.{ Class => jClass }
+import scala.language.implicitConversions
+
+/*
+ * TODO
+ * add @see to docs about universes
+ * [Eugene++] also mention sensitivity to prefixes, i.e. that rb.TypeTag is different from ru.TypeTag
+ * [Chris++] tag.in(some mirror) or expr.in(some mirror) (does not work for tag and exprs in macros)
+ * Backwards compat item1: [Eugene++] it might be useful, though, to guard against abstractness of the incoming type.
+ */
+/**
+ * A type tag encapsulates a representation of type T.
+ *
+ * Type tags replace the pre-2.10 concept of a [[scala.reflect.Manifest]] and are integrated with reflection.
+ *
+ * === Overview and examples ===
+ *
+ * Type tags are organized in a hierarchy of three classes:
+ * [[scala.reflect.ClassTag]], [[scala.reflect.api.Universe#TypeTag]] and [[scala.reflect.api.Universe#WeakTypeTag]].
+ *
+ * @see [[scala.reflect.ClassTag]], [[scala.reflect.api.Universe#TypeTag]], [[scala.reflect.api.Universe#WeakTypeTag]]
+ *
+ * Examples:
+ * {{{
+ * scala> class Person
+ * scala> class Container[T]
+ * scala> import scala.reflect.ClassTag
+ * scala> import scala.reflect.runtime.universe.TypeTag
+ * scala> import scala.reflect.runtime.universe.WeakTypeTag
+ * scala> def firstTypeArg( tag: WeakTypeTag[_] ) = (tag.tpe match {case TypeRef(_,_,typeArgs) => typeArgs})(0)
+ * }}}
+ * TypeTag contains concrete type arguments:
+ * {{{
+ * scala> firstTypeArg( implicitly[TypeTag[Container[Person]]] )
+ * res0: reflect.runtime.universe.Type = Person
+ * }}}
+ * TypeTag guarantees concrete type arguments (fails for references to unbound type arguments):
+ * {{{
+ * scala> def foo1[T] = implicitly[TypeTag[Container[T]]]
+ * <console>:11: error: No TypeTag available for Container[T]
+ * def foo1[T] = implicitly[TypeTag[Container[T]]]
+ * }}}
+ * WeakTypeTag allows references to unbound type arguments:
+ * {{{
+ * scala> def foo2[T] = firstTypeArg( implicitly[WeakTypeTag[Container[T]]] )
+ * foo2: [T]=> reflect.runtime.universe.Type
+ * scala> foo2[Person]
+ * res1: reflect.runtime.universe.Type = T
+ * }}}
+ * TypeTag allows unbound type arguments for which type tags are available:
+ * {{{
+ * scala> def foo3[T:TypeTag] = firstTypeArg( implicitly[TypeTag[Container[T]]] )
+ * foo3: [T](implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.Type
+ * scala> foo3[Person]
+ * res1: reflect.runtime.universe.Type = Person
+ * }}}
+ * WeakTypeTag contains concrete type arguments if available via existing tags:
+ * {{{
+ * scala> def foo4[T:WeakTypeTag] = firstTypeArg( implicitly[WeakTypeTag[Container[T]]] )
+ * foo4: [T](implicit evidence$1: reflect.runtime.universe.WeakTypeTag[T])reflect.runtime.universe.Type
+ * scala> foo4[Person]
+ * res1: reflect.runtime.universe.Type = Person
+ * }}}
+ *
+ *
+ * [[scala.reflect.api.Universe#TypeTag]] and [[scala.reflect.api.Universe#WeakTypeTag]] are path dependent on their universe.
+ *
+ * The default universe is [[scala.reflect.runtime.universe]]
+ *
+ * Type tags can be migrated to another universe given the corresponding mirror using
+ *
+ * {{{
+ * tag.in( other_mirror )
+ * }}}
+ *
+ * See [[scala.reflect.api.TypeTags#WeakTypeTag.in]]
+ *
+ * === WeakTypeTag vs TypeTag ===
+ *
+ * Be careful with WeakTypeTag, because it will reify types even if these types are abstract.
+ * This makes it easy to forget to tag one of the methods in the call chain and discover it much later in the runtime
+ * by getting cryptic errors far away from their source. For example, consider the following snippet:
+ *
+ * {{{
+ * def bind[T: WeakTypeTag](name: String, value: T): IR.Result = bind((name, value))
+ * def bind(p: NamedParam): IR.Result = bind(p.name, p.tpe, p.value)
+ * object NamedParam {
+ * implicit def namedValue[T: WeakTypeTag](name: String, x: T): NamedParam = apply(name, x)
+ * def apply[T: WeakTypeTag](name: String, x: T): NamedParam = new Typed[T](name, x)
+ * }
+ * }}}
+ *
+ * This fragment of the Scala REPL implementation defines a `bind` function that carries a named value along with its type
+ * into the heart of the REPL. Using a [[scala.reflect.api.Universe#WeakTypeTag]] here is reasonable, because it is desirable
+ * to work with all types, even if they are type parameters or abstract type members.
+ *
+ * However if any of the three `WeakTypeTag` context bounds is omitted, the resulting code will be incorrect,
+ * because the missing `WeakTypeTag` will be transparently generated by the compiler, carrying meaningless information.
+ * Most likely, this problem will manifest itself elsewhere, making debugging complicated.
+ * If `WeakTypeTag` context bounds were replaced with `TypeTag`, then such errors would be reported statically.
+ * But in that case we wouldn't be able to use `bind` in arbitrary contexts.
+ *
+ * === Backward compatibility with Manifests ===
+ *
+ * Type tags correspond loosely to manifests.
+ *
+ * More precisely:
+ * The previous notion of a [[scala.reflect.ClassManifest]] corresponds to a scala.reflect.ClassTag,
+ * The previous notion of a [[scala.reflect.Manifest]] corresponds to scala.reflect.runtime.universe.TypeTag,
+ *
+ * In Scala 2.10, manifests are deprecated, so it's advisable to migrate them to tags,
+ * because manifests will probably be removed in the next major release.
+ *
+ * In most cases it will be enough to replace ClassManifest with ClassTag and Manifest with TypeTag.
+ * There are however a few caveats:
+ *
+ * 1) The notion of OptManifest is no longer supported. Tags can reify arbitrary types, so they are always available.
+ *
+ * 2) There's no equivalent for AnyValManifest. Consider comparing your tag with one of the base tags
+ * (defined in the corresponding companion objects) to find out whether it represents a primitive value class.
+ * You can also use `<tag>.tpe.typeSymbol.isPrimitiveValueClass` for that purpose (requires scala-reflect.jar).
+ *
+ * 3) There's no replacement for factory methods defined in `ClassManifest` and `Manifest` companion objects.
+ * Consider assembling corresponding types using the reflection APIs provided by Java (for classes) and Scala (for types).
+ *
+ * 4) Certain manifest functions (such as `<:<`, `>:>` and `typeArguments`) weren't included in the tag API.
+ * Consider using the reflection APIs provided by Java (for classes) and Scala (for types) instead.
+ */
+trait TypeTags { self: Universe =>
+
+ import definitions._
+
+ /**
+ * If an implicit value of type WeakTypeTag[T] is required, the compiler will create one.
+ * A reflective representation of T can be accessed via the tpe field.
+ * Components of T can be references to type parameters or abstract types. WeakTypeTag makes an effort to
+ * be as concrete as possible, i.e. if type tags are available for the referenced type arguments or abstract types,
+ * they are used to embed the concrete types into the WeakTypeTag. Otherwise the WeakTypeTag will contain a reference
+ * to an abstract type. This behavior can be useful, when one expects T to be possibly partially abstract, but
+ * requires special care to handle this case. If however T is expected to be fully known, use
+ * [[scala.reflect.api.Universe#TypeTag]] instead, which statically guarantees this property.
+ *
+ * @see [[scala.reflect.api.TypeTags]]
+ */
+ @annotation.implicitNotFound(msg = "No WeakTypeTag available for ${T}")
+ trait WeakTypeTag[T] extends Equals with Serializable {
+ /**
+ * Mirror corresponding to the universe of this WeakTypeTag.
+ */
+ val mirror: Mirror
+ /**
+ * Migrates type tag to another universe.
+ *
+ * Type tags are path dependent on their universe. This methods allows migration
+ * given the mirror corresponding to the target universe.
+ *
+ * Migration means that all symbolic references to classes/objects/packages in the expression
+ * will be re-resolved within the new mirror (typically using that mirror's classloader).
+ */
+ def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # WeakTypeTag[T]
+
+ /**
+ * Reflective representation of type T.
+ */
+ def tpe: Type
+
+ // case class accessories
+ override def canEqual(x: Any) = x.isInstanceOf[WeakTypeTag[_]]
+ override def equals(x: Any) = x.isInstanceOf[WeakTypeTag[_]] && this.mirror == x.asInstanceOf[WeakTypeTag[_]].mirror && this.tpe == x.asInstanceOf[WeakTypeTag[_]].tpe
+ override def hashCode = mirror.hashCode * 31 + tpe.hashCode
+ override def toString = "WeakTypeTag[" + tpe + "]"
+ }
+
+ /**
+ * Type tags corresponding to primitive types and constructor/extractor for WeakTypeTags.
+ */
+ object WeakTypeTag {
+ val Byte : WeakTypeTag[scala.Byte] = TypeTag.Byte
+ val Short : WeakTypeTag[scala.Short] = TypeTag.Short
+ val Char : WeakTypeTag[scala.Char] = TypeTag.Char
+ val Int : WeakTypeTag[scala.Int] = TypeTag.Int
+ val Long : WeakTypeTag[scala.Long] = TypeTag.Long
+ val Float : WeakTypeTag[scala.Float] = TypeTag.Float
+ val Double : WeakTypeTag[scala.Double] = TypeTag.Double
+ val Boolean : WeakTypeTag[scala.Boolean] = TypeTag.Boolean
+ val Unit : WeakTypeTag[scala.Unit] = TypeTag.Unit
+ val Any : WeakTypeTag[scala.Any] = TypeTag.Any
+ val AnyVal : WeakTypeTag[scala.AnyVal] = TypeTag.AnyVal
+ val AnyRef : WeakTypeTag[scala.AnyRef] = TypeTag.AnyRef
+ val Object : WeakTypeTag[java.lang.Object] = TypeTag.Object
+ val Nothing : WeakTypeTag[scala.Nothing] = TypeTag.Nothing
+ val Null : WeakTypeTag[scala.Null] = TypeTag.Null
+
+
+ def apply[T](mirror1: MirrorOf[self.type], tpec1: TypeCreator): WeakTypeTag[T] =
+ tpec1(mirror1) match {
+ case ByteTpe => WeakTypeTag.Byte.asInstanceOf[WeakTypeTag[T]]
+ case ShortTpe => WeakTypeTag.Short.asInstanceOf[WeakTypeTag[T]]
+ case CharTpe => WeakTypeTag.Char.asInstanceOf[WeakTypeTag[T]]
+ case IntTpe => WeakTypeTag.Int.asInstanceOf[WeakTypeTag[T]]
+ case LongTpe => WeakTypeTag.Long.asInstanceOf[WeakTypeTag[T]]
+ case FloatTpe => WeakTypeTag.Float.asInstanceOf[WeakTypeTag[T]]
+ case DoubleTpe => WeakTypeTag.Double.asInstanceOf[WeakTypeTag[T]]
+ case BooleanTpe => WeakTypeTag.Boolean.asInstanceOf[WeakTypeTag[T]]
+ case UnitTpe => WeakTypeTag.Unit.asInstanceOf[WeakTypeTag[T]]
+ case AnyTpe => WeakTypeTag.Any.asInstanceOf[WeakTypeTag[T]]
+ case AnyValTpe => WeakTypeTag.AnyVal.asInstanceOf[WeakTypeTag[T]]
+ case AnyRefTpe => WeakTypeTag.AnyRef.asInstanceOf[WeakTypeTag[T]]
+ case ObjectTpe => WeakTypeTag.Object.asInstanceOf[WeakTypeTag[T]]
+ case NothingTpe => WeakTypeTag.Nothing.asInstanceOf[WeakTypeTag[T]]
+ case NullTpe => WeakTypeTag.Null.asInstanceOf[WeakTypeTag[T]]
+ case _ => new WeakTypeTagImpl[T](mirror1.asInstanceOf[Mirror], tpec1)
+ }
+
+ def unapply[T](ttag: WeakTypeTag[T]): Option[Type] = Some(ttag.tpe)
+ }
+
+ private class WeakTypeTagImpl[T](val mirror: Mirror, val tpec: TypeCreator) extends WeakTypeTag[T] {
+ lazy val tpe: Type = tpec(mirror)
+ def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # WeakTypeTag[T] = {
+ val otherMirror1 = otherMirror.asInstanceOf[MirrorOf[otherMirror.universe.type]]
+ otherMirror.universe.WeakTypeTag[T](otherMirror1, tpec)
+ }
+ private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = false)
+ }
+
+ /**
+ * A `TypeTag` is a [[scala.reflect.api.Universe#WeakTypeTag]] with the additional
+ * static guarantee that all type references are concrete, i.e. it does <b>not</b> contain any references to
+ * unresolved type parameters or abstract types.
+ *
+ * @see [[scala.reflect.api.TypeTags]]
+ */
+ @annotation.implicitNotFound(msg = "No TypeTag available for ${T}")
+ trait TypeTag[T] extends WeakTypeTag[T] with Equals with Serializable {
+ /**
+ * @inheritdoc
+ */
+ override def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # TypeTag[T]
+
+ // case class accessories
+ override def canEqual(x: Any) = x.isInstanceOf[TypeTag[_]]
+ override def equals(x: Any) = x.isInstanceOf[TypeTag[_]] && this.mirror == x.asInstanceOf[TypeTag[_]].mirror && this.tpe == x.asInstanceOf[TypeTag[_]].tpe
+ override def hashCode = mirror.hashCode * 31 + tpe.hashCode
+ override def toString = "TypeTag[" + tpe + "]"
+ }
+
+ object TypeTag {
+ val Byte: TypeTag[scala.Byte] = new PredefTypeTag[scala.Byte] (ByteTpe, _.TypeTag.Byte)
+ val Short: TypeTag[scala.Short] = new PredefTypeTag[scala.Short] (ShortTpe, _.TypeTag.Short)
+ val Char: TypeTag[scala.Char] = new PredefTypeTag[scala.Char] (CharTpe, _.TypeTag.Char)
+ val Int: TypeTag[scala.Int] = new PredefTypeTag[scala.Int] (IntTpe, _.TypeTag.Int)
+ val Long: TypeTag[scala.Long] = new PredefTypeTag[scala.Long] (LongTpe, _.TypeTag.Long)
+ val Float: TypeTag[scala.Float] = new PredefTypeTag[scala.Float] (FloatTpe, _.TypeTag.Float)
+ val Double: TypeTag[scala.Double] = new PredefTypeTag[scala.Double] (DoubleTpe, _.TypeTag.Double)
+ val Boolean: TypeTag[scala.Boolean] = new PredefTypeTag[scala.Boolean] (BooleanTpe, _.TypeTag.Boolean)
+ val Unit: TypeTag[scala.Unit] = new PredefTypeTag[scala.Unit] (UnitTpe, _.TypeTag.Unit)
+ val Any: TypeTag[scala.Any] = new PredefTypeTag[scala.Any] (AnyTpe, _.TypeTag.Any)
+ val AnyVal: TypeTag[scala.AnyVal] = new PredefTypeTag[scala.AnyVal] (AnyValTpe, _.TypeTag.AnyVal)
+ val AnyRef: TypeTag[scala.AnyRef] = new PredefTypeTag[scala.AnyRef] (AnyRefTpe, _.TypeTag.AnyRef)
+ val Object: TypeTag[java.lang.Object] = new PredefTypeTag[java.lang.Object] (ObjectTpe, _.TypeTag.Object)
+ val Nothing: TypeTag[scala.Nothing] = new PredefTypeTag[scala.Nothing] (NothingTpe, _.TypeTag.Nothing)
+ val Null: TypeTag[scala.Null] = new PredefTypeTag[scala.Null] (NullTpe, _.TypeTag.Null)
+
+ def apply[T](mirror1: MirrorOf[self.type], tpec1: TypeCreator): TypeTag[T] =
+ tpec1(mirror1) match {
+ case ByteTpe => TypeTag.Byte.asInstanceOf[TypeTag[T]]
+ case ShortTpe => TypeTag.Short.asInstanceOf[TypeTag[T]]
+ case CharTpe => TypeTag.Char.asInstanceOf[TypeTag[T]]
+ case IntTpe => TypeTag.Int.asInstanceOf[TypeTag[T]]
+ case LongTpe => TypeTag.Long.asInstanceOf[TypeTag[T]]
+ case FloatTpe => TypeTag.Float.asInstanceOf[TypeTag[T]]
+ case DoubleTpe => TypeTag.Double.asInstanceOf[TypeTag[T]]
+ case BooleanTpe => TypeTag.Boolean.asInstanceOf[TypeTag[T]]
+ case UnitTpe => TypeTag.Unit.asInstanceOf[TypeTag[T]]
+ case AnyTpe => TypeTag.Any.asInstanceOf[TypeTag[T]]
+ case AnyValTpe => TypeTag.AnyVal.asInstanceOf[TypeTag[T]]
+ case AnyRefTpe => TypeTag.AnyRef.asInstanceOf[TypeTag[T]]
+ case ObjectTpe => TypeTag.Object.asInstanceOf[TypeTag[T]]
+ case NothingTpe => TypeTag.Nothing.asInstanceOf[TypeTag[T]]
+ case NullTpe => TypeTag.Null.asInstanceOf[TypeTag[T]]
+ case _ => new TypeTagImpl[T](mirror1.asInstanceOf[Mirror], tpec1)
+ }
+
+ def unapply[T](ttag: TypeTag[T]): Option[Type] = Some(ttag.tpe)
+ }
+
+ private class TypeTagImpl[T](mirror: Mirror, tpec: TypeCreator) extends WeakTypeTagImpl[T](mirror, tpec) with TypeTag[T] {
+ override def in[U <: Universe with Singleton](otherMirror: MirrorOf[U]): U # TypeTag[T] = {
+ val otherMirror1 = otherMirror.asInstanceOf[MirrorOf[otherMirror.universe.type]]
+ otherMirror.universe.TypeTag[T](otherMirror1, tpec)
+ }
+ private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = true)
+ }
+
+ private class PredefTypeCreator[T](copyIn: Universe => Universe#TypeTag[T]) extends TypeCreator {
+ def apply[U <: Universe with Singleton](m: MirrorOf[U]): U # Type = {
+ copyIn(m.universe).asInstanceOf[U # TypeTag[T]].tpe
+ }
+ }
+
+ private class PredefTypeTag[T](_tpe: Type, copyIn: Universe => Universe#TypeTag[T]) extends TypeTagImpl[T](rootMirror, new PredefTypeCreator(copyIn)) {
+ override lazy val tpe: Type = _tpe
+ private def writeReplace(): AnyRef = new SerializedTypeTag(tpec, concrete = true)
+ }
+
+ /**
+ * Shortcut for `implicitly[WeakTypeTag[T]]`
+ */
+ def weakTypeTag[T](implicit attag: WeakTypeTag[T]) = attag
+
+ /**
+ * Shortcut for `implicitly[TypeTag[T]]`
+ */
+ def typeTag[T](implicit ttag: TypeTag[T]) = ttag
+
+ // big thanks to Viktor Klang for this brilliant idea!
+ /**
+ * Shortcut for `implicitly[WeakTypeTag[T]].tpe`
+ */
+ def weakTypeOf[T](implicit attag: WeakTypeTag[T]): Type = attag.tpe
+
+ /**
+ * Shortcut for `implicitly[TypeTag[T]].tpe`
+ */
+ def typeOf[T](implicit ttag: TypeTag[T]): Type = ttag.tpe
+}
+
+private[scala] class SerializedTypeTag(var tpec: TypeCreator, var concrete: Boolean) extends Serializable {
+ private def writeObject(out: java.io.ObjectOutputStream): Unit = {
+ out.writeObject(tpec)
+ out.writeBoolean(concrete)
+ }
+
+ private def readObject(in: java.io.ObjectInputStream): Unit = {
+ tpec = in.readObject().asInstanceOf[TypeCreator]
+ concrete = in.readBoolean()
+ }
+
+ private def readResolve(): AnyRef = {
+ import scala.reflect.runtime.universe._
+ if (concrete) TypeTag(rootMirror, tpec)
+ else WeakTypeTag(rootMirror, tpec)
+ }
+}