diff options
author | Eugene Burmako <xeno.by@gmail.com> | 2012-09-19 15:04:50 +0200 |
---|---|---|
committer | Eugene Burmako <xeno.by@gmail.com> | 2012-09-19 22:47:10 +0200 |
commit | 3fa900ca0ea244ac54df75dc2fd6d711739eface (patch) | |
tree | bd37a549da114d7030a7cbce14ecc527058dd1ad /src/reflect/scala/reflect/api/TypeTags.scala | |
parent | eadf1d2080e0ce763e4c1920a26b80c8b8609ca0 (diff) | |
download | scala-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.scala | 354 |
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) + } +} |