diff options
Diffstat (limited to 'src/library')
-rw-r--r-- | src/library/scala/Predef.scala | 26 | ||||
-rw-r--r-- | src/library/scala/reflect/ArrayTag.scala | 8 | ||||
-rw-r--r-- | src/library/scala/reflect/ClassTag.scala | 206 | ||||
-rw-r--r-- | src/library/scala/reflect/DummyMirror.scala | 2 | ||||
-rw-r--r-- | src/library/scala/reflect/ErasureTag.scala | 23 | ||||
-rw-r--r-- | src/library/scala/reflect/ReflectionUtils.scala | 1 | ||||
-rw-r--r-- | src/library/scala/reflect/TagMaterialization.scala | 122 | ||||
-rwxr-xr-x | src/library/scala/reflect/api/Symbols.scala | 8 | ||||
-rw-r--r-- | src/library/scala/reflect/api/TypeTags.scala | 246 | ||||
-rwxr-xr-x | src/library/scala/reflect/api/Universe.scala | 23 | ||||
-rw-r--r-- | src/library/scala/reflect/makro/Context.scala | 21 | ||||
-rw-r--r-- | src/library/scala/reflect/makro/Reifiers.scala | 25 | ||||
-rw-r--r-- | src/library/scala/reflect/makro/internal/Utils.scala | 86 | ||||
-rw-r--r-- | src/library/scala/reflect/package.scala | 5 | ||||
-rw-r--r-- | src/library/scala/runtime/ScalaRunTime.scala | 21 | ||||
-rw-r--r-- | src/library/scala/util/Marshal.scala | 36 |
16 files changed, 334 insertions, 525 deletions
diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 15e007528b..093f972f72 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -119,20 +119,24 @@ object Predef extends LowPriorityImplicits { def optManifest[T](implicit m: OptManifest[T]) = m // Tag types and companions, and incantations for summoning - type ClassTag[T] = scala.reflect.ClassTag[T] - type TypeTag[T] = scala.reflect.TypeTag[T] - type ConcreteTypeTag[T] = scala.reflect.ConcreteTypeTag[T] - val ClassTag = scala.reflect.ClassTag // doesn't need to be lazy, because it's not a path-dependent type + type ArrayTag[T] = scala.reflect.ArrayTag[T] + type ErasureTag[T] = scala.reflect.ErasureTag[T] + type ClassTag[T] = scala.reflect.ClassTag[T] + type TypeTag[T] = scala.reflect.TypeTag[T] + type ConcreteTypeTag[T] = scala.reflect.ConcreteTypeTag[T] + val ClassTag = scala.reflect.ClassTag // doesn't need to be lazy, because it's not a path-dependent type // [Paul to Eugene] No lazy vals in Predef. Too expensive. Have to work harder on breaking initialization dependencies. - lazy val TypeTag = scala.reflect.TypeTag // needs to be lazy, because requires scala.reflect.mirror instance - lazy val ConcreteTypeTag = scala.reflect.ConcreteTypeTag + lazy val TypeTag = scala.reflect.TypeTag // needs to be lazy, because requires scala.reflect.mirror instance + lazy val ConcreteTypeTag = scala.reflect.ConcreteTypeTag // [Eugene to Martin] it's really tedious to type "implicitly[...]" all the time, so I'm reintroducing these shortcuts - def classTag[T](implicit ctag: ClassTag[T]) = ctag - def tag[T](implicit ttag: TypeTag[T]) = ttag - def typeTag[T](implicit ttag: TypeTag[T]) = ttag - def concreteTag[T](implicit cttag: ConcreteTypeTag[T]) = cttag - def concreteTypeTag[T](implicit cttag: ConcreteTypeTag[T]) = cttag + def arrayTag[T](implicit atag: ArrayTag[T]) = atag + def erasureTag[T](implicit etag: ErasureTag[T]) = etag + def classTag[T](implicit ctag: ClassTag[T]) = ctag + def tag[T](implicit ttag: TypeTag[T]) = ttag + def typeTag[T](implicit ttag: TypeTag[T]) = ttag + def concreteTag[T](implicit cttag: ConcreteTypeTag[T]) = cttag + def concreteTypeTag[T](implicit cttag: ConcreteTypeTag[T]) = cttag // Minor variations on identity functions def identity[A](x: A): A = x // @see `conforms` for the implicit version diff --git a/src/library/scala/reflect/ArrayTag.scala b/src/library/scala/reflect/ArrayTag.scala index 8df7fe5f4e..ba0c075723 100644 --- a/src/library/scala/reflect/ArrayTag.scala +++ b/src/library/scala/reflect/ArrayTag.scala @@ -3,11 +3,17 @@ package scala.reflect /** An `ArrayTag[T]` is a descriptor that is requested by the compiler every time * when an array is instantiated, but the element type is unknown at compile time. * + * Implicit in the contract of `ArrayTag[T]` is the fact that `T` + * cannot contain unresolved references to type parameters or abstract types. + * * Scala library provides a standard implementation of this trait, - * `ClassTag[T]` that explicitly carries the `java.lang.Class` erasure of type T. + * `ClassTag[T]` that explicitly carries the `java.lang.Class` erasure of type T + * and uses Java reflection to instantiate arrays. * * However other platforms (e.g. a Scala -> JS crosscompiler) may reimplement this trait as they see fit * and then expose the implementation via an implicit macro. + * + * @see [[scala.reflect.api.TypeTags]] */ @annotation.implicitNotFound(msg = "No ArrayTag available for ${T}") trait ArrayTag[T] { diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index 142025f600..e485691747 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -3,6 +3,7 @@ package scala.reflect import java.lang.{ Class => jClass } import scala.reflect.{ mirror => rm } import language.{implicitConversions, existentials} +import scala.runtime.ScalaRunTime.arrayClass /** A `ClassTag[T]` wraps a Java class, which can be accessed via the `erasure` method. * @@ -18,34 +19,17 @@ import language.{implicitConversions, existentials} * If the type T contains unresolved references to type parameters or abstract types, a static error results. * * A ConcreteTypeTag member of the reflect.mirror object is convertible to a ClassTag via an implicit conversion - * (this is not possible to do in all reflection universes because an operation that converts a type to a Java class might not be available). */ -// 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 + * (this is not possible to do in all reflection universes because an operation that converts a type to a Java class might not be available). + * + * @see [[scala.reflect.api.TypeTags]] + */ @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 ConcreteTypeTags the representation is almost precise, because they use 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) +trait ClassTag[T] extends ArrayTag[T] with ErasureTag[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 /** Produces a `ClassTag` that knows how to build `Array[Array[T]]` */ - def wrap: ClassTag[Array[T]] = { - // newInstance throws an exception if the erasure is Void.TYPE - // see SI-5680 - val arrayClazz = - if (erasure == java.lang.Void.TYPE) classOf[Array[Unit]] - else java.lang.reflect.Array.newInstance(erasure, 0).getClass.asInstanceOf[jClass[Array[T]]] - ClassTag[Array[T]](arrayClazz) - } + def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](arrayClass(erasure)) /** Produces a new array with element type `T` and length `len` */ def newArray(len: Int): Array[T] = @@ -61,31 +45,39 @@ abstract case class ClassTag[T](erasure: jClass[_]) extends ArrayTag[T] { case java.lang.Void.TYPE => new Array[Unit](len).asInstanceOf[Array[T]] case _ => java.lang.reflect.Array.newInstance(erasure, len).asInstanceOf[Array[T]] } + + /** case class accessories */ + override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]] + override def equals(x: Any) = x.isInstanceOf[ClassTag[_]] && this.erasure == x.asInstanceOf[ClassTag[_]].erasure + override def hashCode = scala.runtime.ScalaRunTime.hash(erasure) + override def toString = "ClassTag[" + erasure + "]" } object ClassTag { + private val NothingTYPE = classOf[scala.runtime.Nothing$] + private val NullTYPE = classOf[scala.runtime.Null$] 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 { + val Byte : ClassTag[scala.Byte] = new ClassTag[scala.Byte]{ def erasure = java.lang.Byte.TYPE; private def readResolve() = ClassTag.Byte } + val Short : ClassTag[scala.Short] = new ClassTag[scala.Short]{ def erasure = java.lang.Short.TYPE; private def readResolve() = ClassTag.Short } + val Char : ClassTag[scala.Char] = new ClassTag[scala.Char]{ def erasure = java.lang.Character.TYPE; private def readResolve() = ClassTag.Char } + val Int : ClassTag[scala.Int] = new ClassTag[scala.Int]{ def erasure = java.lang.Integer.TYPE; private def readResolve() = ClassTag.Int } + val Long : ClassTag[scala.Long] = new ClassTag[scala.Long]{ def erasure = java.lang.Long.TYPE; private def readResolve() = ClassTag.Long } + val Float : ClassTag[scala.Float] = new ClassTag[scala.Float]{ def erasure = java.lang.Float.TYPE; private def readResolve() = ClassTag.Float } + val Double : ClassTag[scala.Double] = new ClassTag[scala.Double]{ def erasure = java.lang.Double.TYPE; private def readResolve() = ClassTag.Double } + val Boolean : ClassTag[scala.Boolean] = new ClassTag[scala.Boolean]{ def erasure = java.lang.Boolean.TYPE; private def readResolve() = ClassTag.Boolean } + val Unit : ClassTag[scala.Unit] = new ClassTag[scala.Unit]{ def erasure = java.lang.Void.TYPE; private def readResolve() = ClassTag.Unit } + val Any : ClassTag[scala.Any] = new ClassTag[scala.Any]{ def erasure = ObjectTYPE; private def readResolve() = ClassTag.Any } + val Object : ClassTag[java.lang.Object] = new ClassTag[java.lang.Object]{ def erasure = ObjectTYPE; private def readResolve() = ClassTag.Object } + val AnyVal : ClassTag[scala.AnyVal] = new ClassTag[scala.AnyVal]{ def erasure = ObjectTYPE; private def readResolve() = ClassTag.AnyVal } + val AnyRef : ClassTag[scala.AnyRef] = new ClassTag[scala.AnyRef]{ def erasure = ObjectTYPE; private def readResolve() = ClassTag.AnyRef } + val Nothing : ClassTag[scala.Nothing] = new ClassTag[scala.Nothing]{ def erasure = NothingTYPE; private def readResolve() = ClassTag.Nothing } + val Null : ClassTag[scala.Null] = new ClassTag[scala.Null]{ def erasure = NullTYPE; private def readResolve() = ClassTag.Null } + val String : ClassTag[java.lang.String] = new ClassTag[java.lang.String]{ def erasure = StringTYPE; private def readResolve() = ClassTag.String } + + def apply[T](erasure1: jClass[_]): ClassTag[T] = + erasure1 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]] @@ -97,128 +89,8 @@ object ClassTag { 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)) + case _ => new ClassTag[T]{ def erasure = erasure1 } } - def apply[T](ttag: rm.ConcreteTypeTag[T]): ClassTag[T] = - if (ttag.erasure != null) ClassTag[T](ttag.erasure) - else ClassTag[T](ttag.tpe) - - implicit def toDeprecatedClassManifestApis[T](ctag: ClassTag[T]): DeprecatedClassManifestApis[T] = new DeprecatedClassManifestApis[T](ctag) - - @deprecated("Use apply instead", "2.10.0") - def fromClass[T](clazz: jClass[T]): ClassManifest[T] = apply(clazz) - - /** Manifest for the singleton type `value.type'. */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def singleType[T <: AnyRef](value: AnyRef): Manifest[T] = ??? - - /** ClassManifest for the class type `clazz', where `clazz' is - * a top-level or static class. - * @note This no-prefix, no-arguments case is separate because we - * it's called from ScalaRunTime.boxArray itself. If we - * pass varargs as arrays into this, we get an infinitely recursive call - * to boxArray. (Besides, having a separate case is more efficient) - */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def classType[T <: AnyRef](clazz: jClass[_]): ClassManifest[T] = ClassTag[T](clazz) - - /** ClassManifest for the class type `clazz[args]', where `clazz' is - * a top-level or static class and `args` are its type arguments */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def classType[T <: AnyRef](clazz: jClass[_], arg1: OptManifest[_], args: OptManifest[_]*): ClassManifest[T] = ClassTag[T](clazz) - - /** ClassManifest for the class type `clazz[args]', where `clazz' is - * a class with non-package prefix type `prefix` and type arguments `args`. - */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def classType[T <: AnyRef](prefix: OptManifest[_], clazz: jClass[_], args: OptManifest[_]*): ClassManifest[T] = ClassTag[T](clazz) - - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def arrayType[T](arg: OptManifest[_]): ClassManifest[Array[T]] = arg match { - case x: ConcreteTypeTag[_] => ClassManifest[Array[T]](x.erasure) - case _ => Object.asInstanceOf[ClassManifest[Array[T]]] // was there in 2.9.x - } - - /** ClassManifest for the abstract type `prefix # name'. `upperBound' is not - * strictly necessary as it could be obtained by reflection. It was - * added so that erasure can be calculated without reflection. */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def abstractType[T](prefix: OptManifest[_], name: String, clazz: jClass[_], args: OptManifest[_]*): ClassManifest[T] = ClassTag[T](clazz) - - /** ClassManifest for the abstract type `prefix # name'. `upperBound' is not - * strictly necessary as it could be obtained by reflection. It was - * added so that erasure can be calculated without reflection. - * todo: remove after next boostrap - */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def abstractType[T](prefix: OptManifest[_], name: String, upperbound: ClassManifest[_], args: OptManifest[_]*): ClassManifest[T] = ClassTag[T](upperbound.erasure) - - 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.ConcreteTypeTag` to capture and analyze type arguments", "2.10.0") - def typeArguments: List[OptManifest[_]] = List() - } -} - + def unapply[T](ctag: ClassTag[T]): Option[Class[_]] = Some(ctag.erasure) +}
\ No newline at end of file diff --git a/src/library/scala/reflect/DummyMirror.scala b/src/library/scala/reflect/DummyMirror.scala index dd4791e57c..8b2ddde2a1 100644 --- a/src/library/scala/reflect/DummyMirror.scala +++ b/src/library/scala/reflect/DummyMirror.scala @@ -430,6 +430,8 @@ class DummyMirror(cl: ClassLoader) extends api.Mirror { def fullName: String = notSupported() def id: Int = notSupported() def orElse[T](alt: => Symbol): Symbol = notSupported() + def filter(cond: Symbol => Boolean): Symbol = notSupported() + def suchThat(cond: Symbol => Boolean): Symbol = notSupported() def privateWithin: Symbol = notSupported() def companionSymbol: Symbol = notSupported() def moduleClass: Symbol = notSupported() diff --git a/src/library/scala/reflect/ErasureTag.scala b/src/library/scala/reflect/ErasureTag.scala new file mode 100644 index 0000000000..f95451fab2 --- /dev/null +++ b/src/library/scala/reflect/ErasureTag.scala @@ -0,0 +1,23 @@ +package scala.reflect + +import java.lang.{Class => jClass} + +/** An `ErasureTag[T]` is a descriptor that is requested by the compiler every time + * when it needs to persist an erasure of a type. + * + * Scala library provides a standard implementation of this trait, + * `TypeTag[T]` that carries the `java.lang.Class` erasure for arbitrary types. + * + * However other platforms may reimplement this trait as they see fit + * and then expose the implementation via an implicit macro. + * + * If you need to guarantee that the type does not contain + * references to type parameters or abstract types, use `ClassTag[T]`. + * + * @see [[scala.reflect.api.TypeTags]] + */ +@annotation.implicitNotFound(msg = "No ErasureTag available for ${T}") +trait ErasureTag[T] { + /** Returns an erasure of type `T` */ + def erasure: jClass[_] +} diff --git a/src/library/scala/reflect/ReflectionUtils.scala b/src/library/scala/reflect/ReflectionUtils.scala index 79a42f6ec4..6ea69cb80d 100644 --- a/src/library/scala/reflect/ReflectionUtils.scala +++ b/src/library/scala/reflect/ReflectionUtils.scala @@ -5,6 +5,7 @@ package scala.reflect +import java.lang.{Class => jClass} import java.lang.reflect.{ InvocationTargetException, UndeclaredThrowableException } /** A few java-reflection oriented utility functions useful during reflection bootstrapping. diff --git a/src/library/scala/reflect/TagMaterialization.scala b/src/library/scala/reflect/TagMaterialization.scala deleted file mode 100644 index e8d4571228..0000000000 --- a/src/library/scala/reflect/TagMaterialization.scala +++ /dev/null @@ -1,122 +0,0 @@ -package scala.reflect - -import api.Universe -import makro.Context -import language.implicitConversions - -// todo. unfortunately, current type inferencer doesn't infer type parameters of implicit values -// this means that during macro expansion these macros will get Nothing instead of real T -// Oh how much I'd love to implement this now, but I have to postpone this until we have a solution for type inference - -/** This object is required by the compiler and <b>should not be used in client code</b>. */ - - /** !!! Some of this code is copy-pasted four places. This situation - * should be resolved ASAP. - */ -object TagMaterialization { - def materializeClassTag[T: c.TypeTag](c: Context): c.Expr[ClassTag[T]] = { - import c.mirror._ - val tpe = implicitly[c.TypeTag[T]].tpe - c.materializeClassTag(tpe) - } - - def materializeTypeTag[T: c.TypeTag](c: Context { type PrefixType = Universe }): c.Expr[c.prefix.value.TypeTag[T]] = { - import c.mirror._ - val tpe = implicitly[c.TypeTag[T]].tpe - c.materializeTypeTag(tpe, requireConcreteTypeTag = false) - } - - def materializeConcreteTypeTag[T: c.TypeTag](c: Context { type PrefixType = Universe }): c.Expr[c.prefix.value.ConcreteTypeTag[T]] = { - import c.mirror._ - val tpe = implicitly[c.TypeTag[T]].tpe - c.materializeTypeTag(tpe, requireConcreteTypeTag = true) - } - - private implicit def context2utils(c0: Context) : Utils { val c: c0.type } = new { val c: c0.type = c0 } with Utils - - private abstract class Utils { - val c: Context - - import c.mirror._ - import definitions._ - - val coreTags = Map( - ByteClass.asType -> newTermName("Byte"), - ShortClass.asType -> newTermName("Short"), - CharClass.asType -> newTermName("Char"), - IntClass.asType -> newTermName("Int"), - LongClass.asType -> newTermName("Long"), - FloatClass.asType -> newTermName("Float"), - DoubleClass.asType -> newTermName("Double"), - BooleanClass.asType -> newTermName("Boolean"), - UnitClass.asType -> newTermName("Unit"), - AnyClass.asType -> newTermName("Any"), - ObjectClass.asType -> newTermName("Object"), - AnyValClass.asType -> newTermName("AnyVal"), - AnyRefClass.asType -> newTermName("AnyRef"), - NothingClass.asType -> newTermName("Nothing"), - NullClass.asType -> newTermName("Null")) - - val ReflectPackage = staticModule("scala.reflect.package") - val Reflect_mirror = selectTerm(ReflectPackage, "mirror") - val ClassTagClass = staticClass("scala.reflect.ClassTag") - val ClassTagErasure = selectTerm(ClassTagClass, "erasure") - val ClassTagModule = staticModule("scala.reflect.ClassTag") - val TypeTagsClass = staticClass("scala.reflect.api.TypeTags") - val TypeTagClass = selectType(TypeTagsClass, "TypeTag") - val TypeTagTpe = selectTerm(TypeTagClass, "tpe") - val TypeTagModule = selectTerm(TypeTagsClass, "TypeTag") - val ConcreteTypeTagClass = selectType(TypeTagsClass, "ConcreteTypeTag") - val ConcreteTypeTagModule = selectTerm(TypeTagsClass, "ConcreteTypeTag") - - def materializeClassTag(tpe: Type): Tree = - materializeTag(c.reflectMirrorPrefix, tpe, ClassTagModule, c.reifyErasure(tpe)) - - def materializeTypeTag(tpe: Type, requireConcreteTypeTag: Boolean): Tree = { - def prefix: Tree = ??? // todo. needs to be synthesized from c.prefix - val tagModule = if (requireConcreteTypeTag) ConcreteTypeTagModule else TypeTagModule - materializeTag(prefix, tpe, tagModule, c.reifyType(prefix, tpe, dontSpliceAtTopLevel = true, requireConcreteTypeTag = requireConcreteTypeTag)) - } - - private def materializeTag(prefix: Tree, tpe: Type, tagModule: Symbol, materializer: => Tree): Tree = { - val result = - tpe match { - case coreTpe if coreTags contains coreTpe => - Select(Select(prefix, tagModule.name), coreTags(coreTpe)) - case _ => - try materializer - catch { - case ex: Throwable => - // [Eugene] cannot pattern match on an abstract type, so had to do this - val ex1 = ex - if (ex.getClass.toString.endsWith("$ReificationError")) { - ex match { - case c.ReificationError(pos, msg) => - c.error(pos, msg) - EmptyTree - } - } else if (ex.getClass.toString.endsWith("$UnexpectedReificationError")) { - ex match { - case c.UnexpectedReificationError(pos, err, cause) => - if (cause != null) throw cause else throw ex - } - } else { - throw ex - } - } - } - try c.typeCheck(result) - catch { case terr @ c.TypeError(pos, msg) => fail(terr) } - } - - private def fail(reason: Any): Nothing = { - val Apply(TypeApply(fun, List(tpeTree)), _) = c.macroApplication - val tpe = tpeTree.tpe - val PolyType(_, MethodType(_, tagTpe)) = fun.tpe - val tagModule = tagTpe.typeSymbol.companionSymbol - if (c.compilerSettings.contains("-Xlog-implicits")) - c.echo(c.enclosingPosition, "cannot materialize " + tagModule.name + "[" + tpe + "] because:\n" + reason) - c.abort(c.enclosingPosition, "No %s available for %s".format(tagModule.name, tpe)) - } - } -} diff --git a/src/library/scala/reflect/api/Symbols.scala b/src/library/scala/reflect/api/Symbols.scala index 767246a294..dbd264c0ab 100755 --- a/src/library/scala/reflect/api/Symbols.scala +++ b/src/library/scala/reflect/api/Symbols.scala @@ -148,6 +148,14 @@ trait Symbols { self: Universe => */ def orElse[T](alt: => Symbol): Symbol + /** ... + */ + def filter(cond: Symbol => Boolean): Symbol + + /** ... + */ + def suchThat(cond: Symbol => Boolean): Symbol + /** * Set when symbol has a modifier of the form private[X], NoSymbol otherwise. * diff --git a/src/library/scala/reflect/api/TypeTags.scala b/src/library/scala/reflect/api/TypeTags.scala index b90475b15a..c58b0fcec2 100644 --- a/src/library/scala/reflect/api/TypeTags.scala +++ b/src/library/scala/reflect/api/TypeTags.scala @@ -6,7 +6,6 @@ package scala.reflect package api -import scala.reflect.{ mirror => rm } import java.lang.{ Class => jClass } import language.implicitConversions @@ -15,22 +14,41 @@ import language.implicitConversions * They are supposed to replace the pre-2.10 concept of a [[scala.reflect.Manifest]]. * TypeTags are much better integrated with reflection than manifests are, and are consequently much simpler. * - * Type tags are organized in a hierarchy of two classes: + * === Overview === + * + * Type tags are organized in a hierarchy of five classes: + * [[scala.reflect.ArrayTag]], [[scala.reflect.ErasureTag]], [[scala.reflect.ClassTag]], * [[scala.reflect.api.Universe#TypeTag]] and [[scala.reflect.api.Universe#ConcreteTypeTag]]. - * A [[scala.reflect.api.Universe#TypeTag]] value wraps a full Scala type in its tpe field. - * A [[scala.reflect.api.Universe#ConcreteTypeTag]] value is a type tag that is guaranteed not to contain any references to type parameters or abstract types. * - * It is also possible to capture Java classes by using a different kind of tag. - * A [[scala.reflect.ClassTag]] value wraps a Java class, which can be accessed via the erasure method. + * An [[scala.reflect.ArrayTag]] value carries knowledge about how to build an array of elements of type T. + * Typically such operation is performed by storing an erasure and instantiating arrays via Java reflection, + * but [[scala.reflect.ArrayTag]] only defines an interface, not an implementation, hence it only contains the factory methods + * `newArray` and `wrap` that can be used to build, correspondingly, single-dimensional and multi-dimensional arrays. * - * TypeTags 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.mirror.ConcreteTypeTag, - * Whereas scala.reflect.mirror.TypeTag is approximated by the previous notion of [[scala.reflect.OptManifest]]. + * An [[scala.reflect.ErasureTag]] value wraps a Java class, which can be accessed via the `erasure` method. + * This notion, previously embodied in a [[scala.reflect.ClassManifest]] together with the notion of array creation, + * deserves a concept of itself. Quite often (e.g. for serialization or classloader introspection) it's useful to + * know an erasure, and only it, so we've implemented this notion in [[scala.reflect.ErasureTag]]. * - * Implicit in the contract for all Tag classes is that the reified type tpe represents the type parameter T. - * Tags are typically created by the compiler, which makes sure that this contract is kept. + * A [[scala.reflect.ClassTag]] is a standard implementation of both [[scala.reflect.ArrayTag]] and [[scala.reflect.ErasureTag]]. + * It guarantees that the source type T did not to contain any references to type parameters or abstract types. + * [[scala.reflect.ClassTag]] corresponds to a previous notion of [[scala.reflect.ClassManifest]]. * + * A [[scala.reflect.api.Universe#TypeTag]] value wraps a full Scala type in its tpe field. + * A [[scala.reflect.api.Universe#ConcreteTypeTag]] value is a [[scala.reflect.api.Universe#TypeTag]] + * that is guaranteed not to contain any references to type parameters or abstract types. + * Both flavors of TypeTags also carry an erasure, so [[scala.reflect.api.Universe#TypeTag]] is also an [[scala.reflect.ErasureTag]], + * and [[scala.reflect.api.Universe#ConcreteTypeTag]] is additionally an [[scala.reflect.ArrayTag]] and a [[scala.reflect.ClassTag]] + * + * It is recommended to use the tag supertypes of to precisely express your intent, i.e.: + * use ArrayTag when you want to construct arrays, + * use ErasureTag when you need an erasure and don't mind it being generated for untagged abstract types, + * use ClassTag only when you need an erasure of a type that doesn't refer to untagged abstract types. + * + * === Splicing === + * + * Tags can be spliced, i.e. if compiler generates a tag for a type that contains references to tagged + * type parameters or abstract type members, it will retrieve the corresponding tag and embed it into the result. * An example that illustrates the TypeTag embedding, consider the following function: * * import reflect.mirror._ @@ -44,6 +62,54 @@ import language.implicitConversions * TypeTag(<[ String => U ]>). * * Note that T has been replaced by String, because it comes with a TypeTag in f, whereas U was left as a type parameter. + * + * === ErasureTag vs ClassTag and TypeTag vs ConcreteTypeTag === + * + * Be careful with ErasureTag and TypeTag, because they 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: TypeTag](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: TypeTag](name: String, x: T): NamedParam = apply(name, x) + * def apply[T: TypeTag](name: String, x: T): NamedParam = new Typed[T](name, x) + * } + * + * This fragment of 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#TypeTag]] 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 `TypeTag` context bounds is omitted, the resulting code will be incorrect, + * because the missing `TypeTag` will be transparently generated by the compiler, carrying meaningless information. + * Most likely, this problem will manifest itself elsewhere, making debugging complicated. + * If `TypeTag` context bounds were replaced with `ConcreteTypeTag`, then such errors would be reported statically. + * But in that case we wouldn't be able to use `bind` in arbitrary contexts. + * + * === Backward compatibility === + * + * TypeTags 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.mirror.ConcreteTypeTag, + * Whereas scala.reflect.mirror.TypeTag is approximated by the previous notion of [[scala.reflect.OptManifest]]. + * + * In Scala 2.10, manifests are deprecated, so it's adviseable to migrate them to tags, + * because manifests might be removed in the next major release. + * + * In most cases it will be enough to replace ClassManifests with ClassTags and Manifests with ConcreteTypeTags, + * however there are a few caveats: + * + * 1) The notion of OptManifest is no longer supported. Tags can reify arbitrary types, so they are always available. + * // [Eugene] it might be useful, though, to guard against abstractness of the incoming type. + * + * 2) There's no equivalent for AnyValManifest. Consider comparing your tag with one of the core tags + * (defined in the corresponding companion objects) to find out whether it represents a primitive value class. + * + * 3) There's no replacement for factory methods defined in `ClassManifest` and `Manifest` companion objects. + * Consider assembling corresponding types using reflection API 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 reflection API provided by Java (for classes) and Scala (for types) instead. */ trait TypeTags { self: Universe => @@ -56,25 +122,20 @@ trait TypeTags { self: Universe => * @see [[scala.reflect.api.TypeTags]] */ @annotation.implicitNotFound(msg = "No TypeTag available for ${T}") - abstract case class TypeTag[T](tpe: Type) { - // it's unsafe to use assert here, because we might run into deadlocks with Predef - // also see comments in ClassTags.scala - // assert(tpe != null) - - def sym = tpe.typeSymbol - def isConcrete = tpe.isConcrete - def notConcrete = !isConcrete - def toConcrete: ConcreteTypeTag[T] = ConcreteTypeTag[T](tpe) - - override def toString = { - if (!self.isInstanceOf[DummyMirror]) { - var prefix = if (isConcrete) "ConcreteTypeTag" else "TypeTag" - if (prefix != this.productPrefix) prefix = "*" + prefix - prefix + "[" + tpe + "]" - } else { - this.productPrefix + "[?]" - } - } + trait TypeTag[T] extends ErasureTag[T] with Equals with Serializable { + + def tpe: Type + def sym: Symbol = tpe.typeSymbol + + def isConcrete: Boolean = tpe.isConcrete + def notConcrete: Boolean = !isConcrete + def toConcrete: ConcreteTypeTag[T] = ConcreteTypeTag[T](tpe, erasure) + + /** case class accessories */ + override def canEqual(x: Any) = x.isInstanceOf[TypeTag[_]] + override def equals(x: Any) = x.isInstanceOf[TypeTag[_]] && this.tpe == x.asInstanceOf[TypeTag[_]].tpe + override def hashCode = scala.runtime.ScalaRunTime.hash(tpe) + override def toString = if (!self.isInstanceOf[DummyMirror]) (if (isConcrete) "*ConcreteTypeTag" else "TypeTag") + "[" + tpe + "]" else "TypeTag[?]" } object TypeTag { @@ -95,8 +156,10 @@ trait TypeTags { self: Universe => val Null : TypeTag[scala.Null] = ConcreteTypeTag.Null val String : TypeTag[java.lang.String] = ConcreteTypeTag.String - def apply[T](tpe: Type): TypeTag[T] = - tpe match { + // todo. uncomment after I redo the starr + // def apply[T](tpe1: Type, erasure1: jClass[_]): TypeTag[T] = + def apply[T](tpe1: Type, erasure1: jClass[_]): TypeTag[T] = + tpe1 match { case ByteTpe => TypeTag.Byte.asInstanceOf[TypeTag[T]] case ShortTpe => TypeTag.Short.asInstanceOf[TypeTag[T]] case CharTpe => TypeTag.Char.asInstanceOf[TypeTag[T]] @@ -113,8 +176,10 @@ trait TypeTags { self: Universe => case NothingTpe => TypeTag.Nothing.asInstanceOf[TypeTag[T]] case NullTpe => TypeTag.Null.asInstanceOf[TypeTag[T]] case StringTpe => TypeTag.String.asInstanceOf[TypeTag[T]] - case _ => new TypeTag[T](tpe) {} + case _ => new TypeTag[T]{ def tpe = tpe1; def erasure = erasure1 } } + + def unapply[T](ttag: TypeTag[T]): Option[Type] = Some(ttag.tpe) } /** @@ -124,36 +189,40 @@ trait TypeTags { self: Universe => * @see [[scala.reflect.api.TypeTags]] */ @annotation.implicitNotFound(msg = "No ConcreteTypeTag available for ${T}") - abstract class ConcreteTypeTag[T](tpe: Type, val erasure: jClass[_]) extends TypeTag[T](tpe) { + trait ConcreteTypeTag[T] extends TypeTag[T] with ClassTag[T] with Equals with Serializable { if (!self.isInstanceOf[DummyMirror]) { -// it's unsafe to use assert here, because we might run into deadlocks with Predef -// also see comments in ClassTags.scala -// assert(isConcrete, tpe) if (notConcrete) throw new Error("%s (%s) is not concrete and cannot be used to construct a concrete type tag".format(tpe, tpe.kind)) } - override def productPrefix = "ConcreteTypeTag" + + /** case class accessories */ + override def canEqual(x: Any) = x.isInstanceOf[TypeTag[_]] // this is done on purpose. TypeTag(tpe) and ConcreteTypeTag(tpe) should be equal if tpe's are equal + override def equals(x: Any) = x.isInstanceOf[TypeTag[_]] && this.tpe == x.asInstanceOf[TypeTag[_]].tpe + override def hashCode = scala.runtime.ScalaRunTime.hash(tpe) + override def toString = if (!self.isInstanceOf[DummyMirror]) "ConcreteTypeTag[" + tpe + "]" else "ConcreteTypeTag[?]" } object ConcreteTypeTag { - val Byte : ConcreteTypeTag[scala.Byte] = new ConcreteTypeTag[scala.Byte](ByteTpe, ClassTag.Byte.erasure) { private def readResolve() = ConcreteTypeTag.Byte } - val Short : ConcreteTypeTag[scala.Short] = new ConcreteTypeTag[scala.Short](ShortTpe, ClassTag.Short.erasure) { private def readResolve() = ConcreteTypeTag.Short } - val Char : ConcreteTypeTag[scala.Char] = new ConcreteTypeTag[scala.Char](CharTpe, ClassTag.Char.erasure) { private def readResolve() = ConcreteTypeTag.Char } - val Int : ConcreteTypeTag[scala.Int] = new ConcreteTypeTag[scala.Int](IntTpe, ClassTag.Int.erasure) { private def readResolve() = ConcreteTypeTag.Int } - val Long : ConcreteTypeTag[scala.Long] = new ConcreteTypeTag[scala.Long](LongTpe, ClassTag.Long.erasure) { private def readResolve() = ConcreteTypeTag.Long } - val Float : ConcreteTypeTag[scala.Float] = new ConcreteTypeTag[scala.Float](FloatTpe, ClassTag.Float.erasure) { private def readResolve() = ConcreteTypeTag.Float } - val Double : ConcreteTypeTag[scala.Double] = new ConcreteTypeTag[scala.Double](DoubleTpe, ClassTag.Double.erasure) { private def readResolve() = ConcreteTypeTag.Double } - val Boolean : ConcreteTypeTag[scala.Boolean] = new ConcreteTypeTag[scala.Boolean](BooleanTpe, ClassTag.Boolean.erasure) { private def readResolve() = ConcreteTypeTag.Boolean } - val Unit : ConcreteTypeTag[scala.Unit] = new ConcreteTypeTag[scala.Unit](UnitTpe, ClassTag.Unit.erasure) { private def readResolve() = ConcreteTypeTag.Unit } - val Any : ConcreteTypeTag[scala.Any] = new ConcreteTypeTag[scala.Any](AnyTpe, ClassTag.Any.erasure) { private def readResolve() = ConcreteTypeTag.Any } - val Object : ConcreteTypeTag[java.lang.Object] = new ConcreteTypeTag[java.lang.Object](ObjectTpe, ClassTag.Object.erasure) { private def readResolve() = ConcreteTypeTag.Object } - val AnyVal : ConcreteTypeTag[scala.AnyVal] = new ConcreteTypeTag[scala.AnyVal](AnyValTpe, ClassTag.AnyVal.erasure) { private def readResolve() = ConcreteTypeTag.AnyVal } - val AnyRef : ConcreteTypeTag[scala.AnyRef] = new ConcreteTypeTag[scala.AnyRef](AnyRefTpe, ClassTag.AnyRef.erasure) { private def readResolve() = ConcreteTypeTag.AnyRef } - val Nothing : ConcreteTypeTag[scala.Nothing] = new ConcreteTypeTag[scala.Nothing](NothingTpe, ClassTag.Nothing.erasure) { private def readResolve() = ConcreteTypeTag.Nothing } - val Null : ConcreteTypeTag[scala.Null] = new ConcreteTypeTag[scala.Null](NullTpe, ClassTag.Null.erasure) { private def readResolve() = ConcreteTypeTag.Null } - val String : ConcreteTypeTag[java.lang.String] = new ConcreteTypeTag[java.lang.String](StringTpe, ClassTag.String.erasure) { private def readResolve() = ConcreteTypeTag.String } - - def apply[T](tpe: Type, erasure: jClass[_] = null): ConcreteTypeTag[T] = - tpe match { + val Byte : ConcreteTypeTag[scala.Byte] = new ConcreteTypeTag[scala.Byte]{ def tpe = ByteTpe; def erasure = ClassTag.Byte.erasure; private def readResolve() = ConcreteTypeTag.Byte } + val Short : ConcreteTypeTag[scala.Short] = new ConcreteTypeTag[scala.Short]{ def tpe = ShortTpe; def erasure = ClassTag.Short.erasure; private def readResolve() = ConcreteTypeTag.Short } + val Char : ConcreteTypeTag[scala.Char] = new ConcreteTypeTag[scala.Char]{ def tpe = CharTpe; def erasure = ClassTag.Char.erasure; private def readResolve() = ConcreteTypeTag.Char } + val Int : ConcreteTypeTag[scala.Int] = new ConcreteTypeTag[scala.Int]{ def tpe = IntTpe; def erasure = ClassTag.Int.erasure; private def readResolve() = ConcreteTypeTag.Int } + val Long : ConcreteTypeTag[scala.Long] = new ConcreteTypeTag[scala.Long]{ def tpe = LongTpe; def erasure = ClassTag.Long.erasure; private def readResolve() = ConcreteTypeTag.Long } + val Float : ConcreteTypeTag[scala.Float] = new ConcreteTypeTag[scala.Float]{ def tpe = FloatTpe; def erasure = ClassTag.Float.erasure; private def readResolve() = ConcreteTypeTag.Float } + val Double : ConcreteTypeTag[scala.Double] = new ConcreteTypeTag[scala.Double]{ def tpe = DoubleTpe; def erasure = ClassTag.Double.erasure; private def readResolve() = ConcreteTypeTag.Double } + val Boolean : ConcreteTypeTag[scala.Boolean] = new ConcreteTypeTag[scala.Boolean]{ def tpe = BooleanTpe; def erasure = ClassTag.Boolean.erasure; private def readResolve() = ConcreteTypeTag.Boolean } + val Unit : ConcreteTypeTag[scala.Unit] = new ConcreteTypeTag[scala.Unit]{ def tpe = UnitTpe; def erasure = ClassTag.Unit.erasure; private def readResolve() = ConcreteTypeTag.Unit } + val Any : ConcreteTypeTag[scala.Any] = new ConcreteTypeTag[scala.Any]{ def tpe = AnyTpe; def erasure = ClassTag.Any.erasure; private def readResolve() = ConcreteTypeTag.Any } + val Object : ConcreteTypeTag[java.lang.Object] = new ConcreteTypeTag[java.lang.Object]{ def tpe = ObjectTpe; def erasure = ClassTag.Object.erasure; private def readResolve() = ConcreteTypeTag.Object } + val AnyVal : ConcreteTypeTag[scala.AnyVal] = new ConcreteTypeTag[scala.AnyVal]{ def tpe = AnyValTpe; def erasure = ClassTag.AnyVal.erasure; private def readResolve() = ConcreteTypeTag.AnyVal } + val AnyRef : ConcreteTypeTag[scala.AnyRef] = new ConcreteTypeTag[scala.AnyRef]{ def tpe = AnyRefTpe; def erasure = ClassTag.AnyRef.erasure; private def readResolve() = ConcreteTypeTag.AnyRef } + val Nothing : ConcreteTypeTag[scala.Nothing] = new ConcreteTypeTag[scala.Nothing]{ def tpe = NothingTpe; def erasure = ClassTag.Nothing.erasure; private def readResolve() = ConcreteTypeTag.Nothing } + val Null : ConcreteTypeTag[scala.Null] = new ConcreteTypeTag[scala.Null]{ def tpe = NullTpe; def erasure = ClassTag.Null.erasure; private def readResolve() = ConcreteTypeTag.Null } + val String : ConcreteTypeTag[java.lang.String] = new ConcreteTypeTag[java.lang.String]{ def tpe = StringTpe; def erasure = ClassTag.String.erasure; private def readResolve() = ConcreteTypeTag.String } + + // todo. uncomment after I redo the starr + // def apply[T](tpe1: Type, erasure1: jClass[_]): ConcreteTypeTag[T] = + def apply[T](tpe1: Type, erasure1: jClass[_] = null): ConcreteTypeTag[T] = + tpe1 match { case ByteTpe => ConcreteTypeTag.Byte.asInstanceOf[ConcreteTypeTag[T]] case ShortTpe => ConcreteTypeTag.Short.asInstanceOf[ConcreteTypeTag[T]] case CharTpe => ConcreteTypeTag.Char.asInstanceOf[ConcreteTypeTag[T]] @@ -170,69 +239,10 @@ trait TypeTags { self: Universe => case NothingTpe => ConcreteTypeTag.Nothing.asInstanceOf[ConcreteTypeTag[T]] case NullTpe => ConcreteTypeTag.Null.asInstanceOf[ConcreteTypeTag[T]] case StringTpe => ConcreteTypeTag.String.asInstanceOf[ConcreteTypeTag[T]] - case _ => new ConcreteTypeTag[T](tpe, erasure) {} + case _ => new ConcreteTypeTag[T]{ def tpe = tpe1; def erasure = erasure1 } } def unapply[T](ttag: TypeTag[T]): Option[Type] = if (ttag.isConcrete) Some(ttag.tpe) else None - - implicit def toClassTag[T](ttag: rm.ConcreteTypeTag[T]): ClassTag[T] = ClassTag[T](ttag) - - implicit def toDeprecatedManifestApis[T](ttag: rm.ConcreteTypeTag[T]): DeprecatedManifestApis[T] = new DeprecatedManifestApis[T](ttag) - - // this class should not be used directly in client code - class DeprecatedManifestApis[T](ttag: rm.ConcreteTypeTag[T]) extends ClassTag.DeprecatedClassManifestApis[T](toClassTag(ttag)) { - @deprecated("Use `tpe` to analyze the underlying type", "2.10.0") - def <:<(that: Manifest[_]): Boolean = ttag.tpe <:< that.tpe - - @deprecated("Use `tpe` to analyze the underlying type", "2.10.0") - def >:>(that: Manifest[_]): Boolean = that <:< ttag - - @deprecated("Use `tpe` to analyze the type arguments", "2.10.0") - override def typeArguments: List[Manifest[_]] = ttag.tpe.typeArguments map (targ => rm.ConcreteTypeTag(targ)) - } - - /** Manifest for the singleton type `value.type'. */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def singleType[T <: AnyRef](value: AnyRef): Manifest[T] = Manifest[T](???, value.getClass) - - /** Manifest for the class type `clazz[args]', where `clazz' is - * a top-level or static class. - * @note This no-prefix, no-arguments case is separate because we - * it's called from ScalaRunTime.boxArray itself. If we - * pass varargs as arrays into this, we get an infinitely recursive call - * to boxArray. (Besides, having a separate case is more efficient) - */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def classType[T](clazz: Predef.Class[_]): Manifest[T] = Manifest[T](???, clazz) - - /** Manifest for the class type `clazz', where `clazz' is - * a top-level or static class and args are its type arguments. */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def classType[T](clazz: Predef.Class[T], arg1: Manifest[_], args: Manifest[_]*): Manifest[T] = Manifest[T](???, clazz) - - /** Manifest for the class type `clazz[args]', where `clazz' is - * a class with non-package prefix type `prefix` and type arguments `args`. - */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def classType[T](prefix: Manifest[_], clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] = Manifest[T](???, clazz) - - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def arrayType[T](arg: Manifest[_]): Manifest[Array[T]] = Manifest[Array[T]](???, arg.asInstanceOf[Manifest[T]].arrayManifest.erasure) - - /** Manifest for the abstract type `prefix # name'. `upperBound' is not - * strictly necessary as it could be obtained by reflection. It was - * added so that erasure can be calculated without reflection. */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def abstractType[T](prefix: Manifest[_], name: String, clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] = Manifest[T](???, clazz) - - /** Manifest for the unknown type `_ >: L <: U' in an existential. - */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def wildcardType[T](lowerBound: Manifest[_], upperBound: Manifest[_]): Manifest[T] = Manifest[T](???, upperBound.erasure) - - /** Manifest for the intersection type `parents_0 with ... with parents_n'. */ - @deprecated("Manifests aka type tags now support arbitrary types. Build a manifest directly from the type instead", "2.10.0") - def intersectionType[T](parents: Manifest[_]*): Manifest[T] = Manifest[T](???, parents.head.erasure) } // incantations for summoning diff --git a/src/library/scala/reflect/api/Universe.scala b/src/library/scala/reflect/api/Universe.scala index 2b22839d39..2a7445c41c 100755 --- a/src/library/scala/reflect/api/Universe.scala +++ b/src/library/scala/reflect/api/Universe.scala @@ -1,5 +1,6 @@ package scala.reflect package api + import language.experimental.macros abstract class Universe extends Symbols @@ -65,25 +66,7 @@ abstract class Universe extends Symbols object Universe { def reify[T](cc: scala.reflect.makro.Context{ type PrefixType = Universe })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = { import cc.mirror._ - try cc.reifyTree(cc.prefix, expr) - catch { - case ex: Throwable => - // [Eugene] cannot pattern match on an abstract type, so had to do this - val ex1 = ex - if (ex.getClass.toString.endsWith("$ReificationError")) { - ex match { - case cc.ReificationError(pos, msg) => - cc.error(pos, msg) - EmptyTree - } - } else if (ex.getClass.toString.endsWith("$UnexpectedReificationError")) { - ex match { - case cc.UnexpectedReificationError(pos, err, cause) => - if (cause != null) throw cause else throw ex - } - } else { - throw ex - } - } + import scala.reflect.makro.internal._ + cc.materializeExpr(cc.prefix, expr) } } diff --git a/src/library/scala/reflect/makro/Context.scala b/src/library/scala/reflect/makro/Context.scala index b304d98a5a..668d239087 100644 --- a/src/library/scala/reflect/makro/Context.scala +++ b/src/library/scala/reflect/makro/Context.scala @@ -34,28 +34,11 @@ trait Context extends Aliases object Context { def reify[T](cc: Context{ type PrefixType = Context })(expr: cc.Expr[T]): cc.Expr[cc.prefix.value.Expr[T]] = { import cc.mirror._ + import scala.reflect.makro.internal._ // [Eugene] how do I typecheck this without undergoing this tiresome (and, in general, incorrect) procedure? val prefix: Tree = Select(cc.prefix, newTermName("mirror")) val prefixTpe = cc.typeCheck(TypeApply(Select(prefix, newTermName("asInstanceOf")), List(SingletonTypeTree(prefix)))).tpe prefix setType prefixTpe - try cc.reifyTree(prefix, expr) - catch { - case ex: Throwable => - // [Eugene] cannot pattern match on an abstract type, so had to do this - if (ex.getClass.toString.endsWith("$ReificationError")) { - ex match { - case cc.ReificationError(pos, msg) => - cc.error(pos, msg) - EmptyTree - } - } else if (ex.getClass.toString.endsWith("$UnexpectedReificationError")) { - ex match { - case cc.UnexpectedReificationError(pos, err, cause) => - if (cause != null) throw cause else throw ex - } - } else { - throw ex - } - } + cc.materializeExpr(prefix, expr) } } diff --git a/src/library/scala/reflect/makro/Reifiers.scala b/src/library/scala/reflect/makro/Reifiers.scala index b9e82e0387..ae6669946c 100644 --- a/src/library/scala/reflect/makro/Reifiers.scala +++ b/src/library/scala/reflect/makro/Reifiers.scala @@ -46,11 +46,12 @@ trait Reifiers { * The produced tree will be bound to the mirror specified by ``prefix'' (also see ``reflectMirrorPrefix''). * For more information and examples see the documentation for ``Context.reifyTree'' and ``Universe.reify''. */ - def reifyType(prefix: Tree, tpe: Type, dontSpliceAtTopLevel: Boolean = false, requireConcreteTypeTag: Boolean = false): Tree + def reifyType(prefix: Tree, tpe: Type, dontSpliceAtTopLevel: Boolean = false, concrete: Boolean = false): Tree /** Given a type, generate a tree that when compiled and executed produces the erasure of the original type. + * If ``concrete'' is true, then this function will bail on types, whose erasure includes abstract types (like `ClassTag` does). */ - def reifyErasure(tpe: Type): Tree + def reifyErasure(tpe: Type, concrete: Boolean = true): Tree /** Undoes reification of a tree. * @@ -67,20 +68,10 @@ trait Reifiers { * 3) compileAndEval(unreifyTree(reifyTree(tree))) ~ compileAndEval(tree) // at runtime original and unreified trees are behaviorally equivalent */ def unreifyTree(tree: Tree): Tree +} - /** Represents an error during reification - */ - type ReificationError <: Throwable - val ReificationError: ReificationErrorExtractor - abstract class ReificationErrorExtractor { - def unapply(error: ReificationError): Option[(Position, String)] - } +// made these guys non path-dependent, otherwise exception handling quickly becomes a mess - /** Wraps an unexpected error during reification - */ - type UnexpectedReificationError <: Throwable - val UnexpectedReificationError: UnexpectedReificationErrorExtractor - abstract class UnexpectedReificationErrorExtractor { - def unapply(error: UnexpectedReificationError): Option[(Position, String, Throwable)] - } -} +case class ReificationError(var pos: reflect.api.Position, val msg: String) extends Throwable(msg) + +case class UnexpectedReificationError(val pos: reflect.api.Position, val msg: String, val cause: Throwable = null) extends Throwable(msg)
\ No newline at end of file diff --git a/src/library/scala/reflect/makro/internal/Utils.scala b/src/library/scala/reflect/makro/internal/Utils.scala index 604bba10b6..a8a2c98715 100644 --- a/src/library/scala/reflect/makro/internal/Utils.scala +++ b/src/library/scala/reflect/makro/internal/Utils.scala @@ -7,6 +7,20 @@ import language.experimental.macros /** This package is required by the compiler and <b>should not be used in client code</b>. */ package object internal { /** This method is required by the compiler and <b>should not be used in client code</b>. */ + def materializeArrayTag[T](u: Universe): ArrayTag[T] = macro materializeArrayTag_impl[T] + + /** This method is required by the compiler and <b>should not be used in client code</b>. */ + def materializeArrayTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[ArrayTag[T]] = + c.Expr[Nothing](c.materializeArrayTag(u.tree, implicitly[c.TypeTag[T]].tpe))(c.TypeTag.Nothing) + + /** This method is required by the compiler and <b>should not be used in client code</b>. */ + def materializeErasureTag[T](u: Universe): ErasureTag[T] = macro materializeErasureTag_impl[T] + + /** This method is required by the compiler and <b>should not be used in client code</b>. */ + def materializeErasureTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[ErasureTag[T]] = + c.Expr[Nothing](c.materializeErasureTag(u.tree, implicitly[c.TypeTag[T]].tpe, concrete = false))(c.TypeTag.Nothing) + + /** This method is required by the compiler and <b>should not be used in client code</b>. */ def materializeClassTag[T](u: Universe): ClassTag[T] = macro materializeClassTag_impl[T] /** This method is required by the compiler and <b>should not be used in client code</b>. */ @@ -18,14 +32,14 @@ package object internal { /** This method is required by the compiler and <b>should not be used in client code</b>. */ def materializeTypeTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[u.value.TypeTag[T]] = - c.Expr[Nothing](c.materializeTypeTag(u.tree, implicitly[c.TypeTag[T]].tpe, requireConcreteTypeTag = false))(c.TypeTag.Nothing) + c.Expr[Nothing](c.materializeTypeTag(u.tree, implicitly[c.TypeTag[T]].tpe, concrete = false))(c.TypeTag.Nothing) /** This method is required by the compiler and <b>should not be used in client code</b>. */ def materializeConcreteTypeTag[T](u: Universe): u.ConcreteTypeTag[T] = macro materializeConcreteTypeTag_impl[T] /** This method is required by the compiler and <b>should not be used in client code</b>. */ def materializeConcreteTypeTag_impl[T: c.TypeTag](c: Context)(u: c.Expr[Universe]): c.Expr[u.value.ConcreteTypeTag[T]] = - c.Expr[Nothing](c.materializeTypeTag(u.tree, implicitly[c.TypeTag[T]].tpe, requireConcreteTypeTag = true))(c.TypeTag.Nothing) + c.Expr[Nothing](c.materializeTypeTag(u.tree, implicitly[c.TypeTag[T]].tpe, concrete = true))(c.TypeTag.Nothing) /** This method is required by the compiler and <b>should not be used in client code</b>. */ private[scala] implicit def context2utils(c0: Context) : Utils { val c: c0.type } = new { val c: c0.type = c0 } with Utils @@ -53,14 +67,27 @@ package internal { AnyValClass.asType -> newTermName("AnyVal"), AnyRefClass.asType -> newTermName("AnyRef"), NothingClass.asType -> newTermName("Nothing"), - NullClass.asType -> newTermName("Null")) + NullClass.asType -> newTermName("Null"), + StringClass.asType -> newTermName("String")) + + // todo. the following two methods won't be necessary once we implement implicit macro generators for tags + + def materializeArrayTag(prefix: Tree, tpe: Type): Tree = + materializeClassTag(prefix, tpe) + + def materializeErasureTag(prefix: Tree, tpe: Type, concrete: Boolean): Tree = + if (concrete) materializeClassTag(prefix, tpe) else materializeTypeTag(prefix, tpe, concrete = false) def materializeClassTag(prefix: Tree, tpe: Type): Tree = - materializeTag(prefix, tpe, ClassTagModule, c.reifyErasure(tpe)) + materializeTag(prefix, tpe, ClassTagModule, { + val erasure = c.reifyErasure(tpe, concrete = true) + val factory = TypeApply(Select(Ident(ClassTagModule), "apply"), List(TypeTree(tpe))) + Apply(factory, List(erasure)) + }) - def materializeTypeTag(prefix: Tree, tpe: Type, requireConcreteTypeTag: Boolean): Tree = { - val tagModule = if (requireConcreteTypeTag) ConcreteTypeTagModule else TypeTagModule - materializeTag(prefix, tpe, tagModule, c.reifyType(prefix, tpe, dontSpliceAtTopLevel = true, requireConcreteTypeTag = requireConcreteTypeTag)) + def materializeTypeTag(prefix: Tree, tpe: Type, concrete: Boolean): Tree = { + val tagModule = if (concrete) ConcreteTypeTagModule else TypeTagModule + materializeTag(prefix, tpe, tagModule, c.reifyType(prefix, tpe, dontSpliceAtTopLevel = true, concrete = concrete)) } private def materializeTag(prefix: Tree, tpe: Type, tagModule: Symbol, materializer: => Tree): Tree = { @@ -70,32 +97,30 @@ package internal { val ref = if (tagModule.owner.isPackageClass) Ident(tagModule) else Select(prefix, tagModule.name) Select(ref, coreTags(coreTpe)) case _ => - try materializer - catch { - case ex: Throwable => - // [Eugene] cannot pattern match on an abstract type, so had to do this - val ex1 = ex - if (ex.getClass.toString.endsWith("$ReificationError")) { - ex match { - case c.ReificationError(pos, msg) => - c.error(pos, msg) - EmptyTree - } - } else if (ex.getClass.toString.endsWith("$UnexpectedReificationError")) { - ex match { - case c.UnexpectedReificationError(pos, err, cause) => - if (cause != null) throw cause else throw ex - } - } else { - throw ex - } - } + translatingReificationErrors(materializer) } try c.typeCheck(result) - catch { case terr @ c.TypeError(pos, msg) => fail(terr) } + catch { case terr @ c.TypeError(pos, msg) => failTag(terr) } + } + + def materializeExpr(prefix: Tree, expr: Tree): Tree = { + val result = translatingReificationErrors(c.reifyTree(prefix, expr)) + try c.typeCheck(result) + catch { case terr @ c.TypeError(pos, msg) => failExpr(terr) } + } + + private def translatingReificationErrors(materializer: => Tree): Tree = { + try materializer + catch { + case ReificationError(pos, msg) => + c.error(pos.asInstanceOf[c.Position], msg) // this cast is a very small price for the sanity of exception handling + EmptyTree + case UnexpectedReificationError(pos, err, cause) if cause != null => + throw cause + } } - private def fail(reason: Any): Nothing = { + private def failTag(reason: Any): Nothing = { val Apply(TypeApply(fun, List(tpeTree)), _) = c.macroApplication val tpe = tpeTree.tpe val PolyType(_, MethodType(_, tagTpe)) = fun.tpe @@ -104,5 +129,8 @@ package internal { c.echo(c.enclosingPosition, "cannot materialize " + tagModule.name + "[" + tpe + "] because:\n" + reason) c.abort(c.enclosingPosition, "No %s available for %s".format(tagModule.name, tpe)) } + + private def failExpr(reason: Any): Nothing = + c.abort(c.enclosingPosition, "Cannot materialize Expr because:\n" + reason) } } diff --git a/src/library/scala/reflect/package.scala b/src/library/scala/reflect/package.scala index 0958f2ce9a..640cad6c21 100644 --- a/src/library/scala/reflect/package.scala +++ b/src/library/scala/reflect/package.scala @@ -65,8 +65,11 @@ package object reflect { @deprecated("Use `@scala.reflect.ConcreteTypeTag` instead", "2.10.0") lazy val Manifest = ConcreteTypeTag @deprecated("NoManifest is no longer supported, and using it may lead to incorrect results, Use `@scala.reflect.TypeTag` instead", "2.10.0") - object NoManifest extends OptManifest[Nothing](scala.reflect.mirror.TypeTag.Nothing.tpe) + lazy val NoManifest = TypeTag.Nothing + // ArrayTag trait is defined separately from the mirror + // ErasureTag trait is defined separately from the mirror + // ConcreteErasureTag trait is defined separately from the mirror // ClassTag class is defined separately from the mirror type TypeTag[T] = scala.reflect.mirror.TypeTag[T] type ConcreteTypeTag[T] = scala.reflect.mirror.ConcreteTypeTag[T] diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index d2adc26d66..9d67644d61 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -47,12 +47,29 @@ object ScalaRunTime { names.toSet } + /** Return the class object representing an array with element class `clazz`. + */ + def arrayClass(clazz: Class[_]): Class[_] = { + // newInstance throws an exception if the erasure is Void.TYPE. see SI-5680 + if (clazz == java.lang.Void.TYPE) classOf[Array[Unit]] + else java.lang.reflect.Array.newInstance(clazz, 0).getClass + } + + /** Return the class object representing elements in arrays described by a given schematic. + */ + def arrayElementClass(schematic: Any): Class[_] = schematic match { + case cls: Class[_] => cls.getComponentType + case tag: ClassTag[_] => tag.erasure + case tag: ArrayTag[_] => tag.newArray(0).getClass.getComponentType + case _ => throw new UnsupportedOperationException("unsupported schematic %s (%s)".format(schematic, if (schematic == null) "null" else schematic.getClass)) + } + /** Return the class object representing an unboxed value type, * e.g. classOf[int], not classOf[java.lang.Integer]. The compiler * rewrites expressions like 5.getClass to come here. */ - def anyValClass[T <: AnyVal : ClassManifest](value: T): Class[T] = - classManifest[T].erasure.asInstanceOf[Class[T]] + def anyValClass[T <: AnyVal : ClassTag](value: T): Class[T] = + classTag[T].erasure.asInstanceOf[Class[T]] /** Retrieve generic array element */ def array_apply(xs: AnyRef, idx: Int): Any = xs match { diff --git a/src/library/scala/util/Marshal.scala b/src/library/scala/util/Marshal.scala index c2269cde45..6eb58e8570 100644 --- a/src/library/scala/util/Marshal.scala +++ b/src/library/scala/util/Marshal.scala @@ -11,19 +11,19 @@ package scala.util /** - * Marshalling of Scala objects using Scala manifests. + * Marshalling of Scala objects using Scala tags. * * @author Stephane Micheloud * @version 1.0 */ object Marshal { import java.io._ - import scala.reflect.ClassManifest + import scala.reflect.ClassTag - def dump[A](o: A)(implicit m: ClassManifest[A]): Array[Byte] = { + def dump[A](o: A)(implicit t: ClassTag[A]): Array[Byte] = { val ba = new ByteArrayOutputStream(512) val out = new ObjectOutputStream(ba) - out.writeObject(m) + out.writeObject(t) out.writeObject(o) out.close() ba.toByteArray() @@ -32,20 +32,20 @@ object Marshal { @throws(classOf[IOException]) @throws(classOf[ClassCastException]) @throws(classOf[ClassNotFoundException]) - def load[A](buffer: Array[Byte])(implicit expected: ClassManifest[A]): A = { + def load[A](buffer: Array[Byte])(implicit expected: ClassTag[A]): A = { val in = new ObjectInputStream(new ByteArrayInputStream(buffer)) - val found = in.readObject.asInstanceOf[ClassManifest[_]] - // todo. [Eugene] needs review, since ClassManifests no longer capture typeArguments - if (found.tpe <:< expected.tpe) { - val o = in.readObject.asInstanceOf[A] - in.close() - o - } else { - in.close() - throw new ClassCastException("type mismatch;"+ - "\n found : "+found+ - "\n required: "+expected) + val found = in.readObject.asInstanceOf[ClassTag[_]] + try { + // [Eugene] needs review + // previously was: found <:< expected + found.erasure.asSubclass(expected.erasure) + in.readObject.asInstanceOf[A] + } catch { + case _: ClassCastException => + in.close() + throw new ClassCastException("type mismatch;"+ + "\n found : "+found+ + "\n required: "+expected) } } - -} +}
\ No newline at end of file |