From f54e5c8bbdd719b5c9375c64c2f66b841984456e Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Sun, 22 Apr 2012 18:49:09 +0200 Subject: resurrects manifests in their pre-2.10 glory --- .../scala/reflect/internal/Definitions.scala | 7 + src/compiler/scala/tools/nsc/ast/TreeGen.scala | 16 ++ .../scala/tools/nsc/typechecker/Implicits.scala | 107 ++++++++- src/library/scala/Predef.scala | 11 +- .../scala/collection/mutable/WrappedArray.scala | 2 +- src/library/scala/reflect/ClassManifest.scala | 242 +++++++++++++++++++ src/library/scala/reflect/Manifest.scala | 259 +++++++++++++++++++++ src/library/scala/reflect/NoManifest.scala | 16 ++ src/library/scala/reflect/OptManifest.scala | 18 ++ src/library/scala/reflect/package.scala | 14 -- 10 files changed, 667 insertions(+), 25 deletions(-) create mode 100644 src/library/scala/reflect/ClassManifest.scala create mode 100644 src/library/scala/reflect/Manifest.scala create mode 100644 src/library/scala/reflect/NoManifest.scala create mode 100644 src/library/scala/reflect/OptManifest.scala (limited to 'src') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 29eb573b64..6cb935edad 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -485,6 +485,13 @@ trait Definitions extends reflect.api.StandardDefinitions { // [Eugene] is this a good place for ReflectMirrorPrefix? def ReflectMirrorPrefix = gen.mkAttributedRef(ReflectMirror) setType singleType(ReflectMirror.owner.thisPrefix, ReflectMirror) + lazy val PartialManifestClass = getRequiredClass("scala.reflect.ClassManifest") + lazy val PartialManifestModule = getRequiredModule("scala.reflect.ClassManifest") + lazy val FullManifestClass = getRequiredClass("scala.reflect.Manifest") + lazy val FullManifestModule = getRequiredModule("scala.reflect.Manifest") + lazy val OptManifestClass = getRequiredClass("scala.reflect.OptManifest") + lazy val NoManifest = getRequiredModule("scala.reflect.NoManifest") + lazy val ExprClass = getMember(getRequiredClass("scala.reflect.api.Exprs"), tpnme.Expr) def ExprTree = getMemberClass(ExprClass, nme.tree) def ExprTpe = getMemberClass(ExprClass, nme.tpe) diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index d3e64811d3..978d83616b 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -177,6 +177,22 @@ abstract class TreeGen extends reflect.internal.TreeGen with TreeDSL { def mkSysErrorCall(message: String): Tree = mkMethodCall(Sys_error, List(Literal(Constant(message)))) + /** A creator for a call to a scala.reflect.Manifest or ClassManifest factory method. + * + * @param full full or partial manifest (target will be Manifest or ClassManifest) + * @param constructor name of the factory method (e.g. "classType") + * @param tparg the type argument + * @param args value arguments + * @return the tree + */ + def mkManifestFactoryCall(full: Boolean, constructor: String, tparg: Type, args: List[Tree]): Tree = + mkMethodCall( + if (full) FullManifestModule else PartialManifestModule, + newTermName(constructor), + List(tparg), + args + ) + /** Make a synchronized block on 'monitor'. */ def mkSynchronized(monitor: Tree, body: Tree): Tree = Apply(Select(monitor, Object_synchronized), List(body)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 3f4e941ec6..fadb691cb6 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -1129,7 +1129,10 @@ trait Implicits { ConcreteTypeTagClass -> MacroInternal_materializeConcreteTypeTag ) - def tagOfType(pre: Type, tp: Type, tagClass: Symbol): SearchResult = { + /** Creates a tree will produce a tag of the requested flavor. + * An EmptyTree is returned if materialization fails. + */ + private def tagOfType(pre: Type, tp: Type, tagClass: Symbol): SearchResult = { def success(arg: Tree) = try { val tree1 = typed(atPos(pos.focus)(arg)) @@ -1171,9 +1174,111 @@ trait Implicits { else failure(materializer, "macros are disabled") } + private val ManifestSymbols = Set[Symbol](PartialManifestClass, FullManifestClass, OptManifestClass) + + /** Creates a tree that calls the relevant factory method in object + * reflect.Manifest for type 'tp'. An EmptyTree is returned if + * no manifest is found. todo: make this instantiate take type params as well? + */ + private def manifestOfType(tp: Type, full: Boolean): SearchResult = { + + /** Creates a tree that calls the factory method called constructor in object reflect.Manifest */ + def manifestFactoryCall(constructor: String, tparg: Type, args: Tree*): Tree = + if (args contains EmptyTree) EmptyTree + else typedPos(tree.pos.focus) { + val mani = gen.mkManifestFactoryCall(full, constructor, tparg, args.toList) + if (settings.debug.value) println("generated manifest: "+mani) // DEBUG + mani + } + + /** Creates a tree representing one of the singleton manifests.*/ + def findSingletonManifest(name: String) = typedPos(tree.pos.focus) { + Select(gen.mkAttributedRef(FullManifestModule), name) + } + + /** Re-wraps a type in a manifest before calling inferImplicit on the result */ + def findManifest(tp: Type, manifestClass: Symbol = if (full) FullManifestClass else PartialManifestClass) = + inferImplicit(tree, appliedType(manifestClass, tp), true, false, context).tree + + def findSubManifest(tp: Type) = findManifest(tp, if (full) FullManifestClass else OptManifestClass) + def mot(tp0: Type, from: List[Symbol], to: List[Type]): SearchResult = { + implicit def wrapResult(tree: Tree): SearchResult = + if (tree == EmptyTree) SearchFailure else new SearchResult(tree, if (from.isEmpty) EmptyTreeTypeSubstituter else new TreeTypeSubstituter(from, to)) + + val tp1 = tp0.normalize + tp1 match { + case ThisType(_) | SingleType(_, _) => + // can't generate a reference to a value that's abstracted over by an existential + if (containsExistential(tp1)) EmptyTree + else manifestFactoryCall("singleType", tp, gen.mkAttributedQualifier(tp1)) + case ConstantType(value) => + manifestOfType(tp1.deconst, full) + case TypeRef(pre, sym, args) => + if (isPrimitiveValueClass(sym) || isPhantomClass(sym)) { + findSingletonManifest(sym.name.toString) + } else if (sym == ObjectClass || sym == AnyRefClass) { + findSingletonManifest("Object") + } else if (sym == RepeatedParamClass || sym == ByNameParamClass) { + EmptyTree + } else if (sym == ArrayClass && args.length == 1) { + manifestFactoryCall("arrayType", args.head, findManifest(args.head)) + } else if (sym.isClass) { + val classarg0 = gen.mkClassOf(tp1) + val classarg = tp match { + case _: ExistentialType => gen.mkCast(classarg0, ClassType(tp)) + case _ => classarg0 + } + val suffix = classarg :: (args map findSubManifest) + manifestFactoryCall( + "classType", tp, + (if ((pre eq NoPrefix) || pre.typeSymbol.isStaticOwner) suffix + else findSubManifest(pre) :: suffix): _*) + } else if (sym.isExistentiallyBound && full) { + manifestFactoryCall("wildcardType", tp, + findManifest(tp.bounds.lo), findManifest(tp.bounds.hi)) + } + // looking for a manifest of a type parameter that hasn't been inferred by now, + // can't do much, but let's not fail + else if (undetParams contains sym) { + // #3859: need to include the mapping from sym -> NothingClass.tpe in the SearchResult + mot(NothingClass.tpe, sym :: from, NothingClass.tpe :: to) + } else { + // a manifest should have been found by normal searchImplicit + EmptyTree + } + case RefinedType(parents, decls) => // !!! not yet: if !full || decls.isEmpty => + // refinement is not generated yet + if (hasLength(parents, 1)) findManifest(parents.head) + else if (full) manifestFactoryCall("intersectionType", tp, parents map findSubManifest: _*) + else mot(erasure.intersectionDominator(parents), from, to) + case ExistentialType(tparams, result) => + mot(tp1.skolemizeExistential, from, to) + case _ => + EmptyTree +/* !!! the following is almost right, but we have to splice nested manifest + * !!! types into this type. This requires a substantial extension of + * !!! reifiers. + val reifier = new Reifier() + val rtree = reifier.reifyTopLevel(tp1) + manifestFactoryCall("apply", tp, rtree) +*/ + } + } + + mot(tp, Nil, Nil) + } + + def wrapResult(tree: Tree): SearchResult = + if (tree == EmptyTree) SearchFailure else new SearchResult(tree, EmptyTreeTypeSubstituter) + /** The tag corresponding to type `pt`, provided `pt` is a flavor of a tag. */ private def implicitTagOrOfExpectedType(pt: Type): SearchResult = pt.dealias match { + case TypeRef(pre, sym, arg :: Nil) if ManifestSymbols(sym) => + manifestOfType(arg, sym == FullManifestClass) match { + case SearchFailure if sym == OptManifestClass => wrapResult(gen.mkAttributedRef(NoManifest)) + case result => result + } case TypeRef(pre, sym, arg :: Nil) if TagSymbols(sym) => tagOfType(pre, arg, sym) case tp@TypeRef(_, sym, _) if sym.isAbstractType => diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 093f972f72..d2aa3a8b34 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -100,19 +100,12 @@ object Predef extends LowPriorityImplicits { // def AnyRef = scala.AnyRef // Manifest types, companions, and incantations for summoning - @deprecated("Use `@scala.reflect.ClassTag` instead", "2.10.0") type ClassManifest[T] = scala.reflect.ClassManifest[T] - @deprecated("OptManifest is no longer supported and using it may lead to incorrect results, use `@scala.reflect.TypeTag` instead", "2.10.0") type OptManifest[T] = scala.reflect.OptManifest[T] - @deprecated("Use `@scala.reflect.ConcreteTypeTag` instead", "2.10.0") type Manifest[T] = scala.reflect.Manifest[T] - @deprecated("Use `@scala.reflect.ClassTag` instead", "2.10.0") val ClassManifest = scala.reflect.ClassManifest - // [Paul to Eugene] No lazy vals in Predef. Too expensive. Have to work harder on breaking initialization dependencies. - @deprecated("Use `@scala.reflect.ConcreteTypeTag` instead", "2.10.0") - lazy val Manifest = scala.reflect.Manifest // needs to be lazy, because requires scala.reflect.mirror instance - @deprecated("NoManifest is no longer supported and using it may lead to incorrect results, use `@scala.reflect.TypeTag` instead", "2.10.0") - lazy val NoManifest = scala.reflect.NoManifest // needs to be lazy, because requires scala.reflect.mirror instance + val Manifest = scala.reflect.Manifest + val NoManifest = scala.reflect.NoManifest def manifest[T](implicit m: Manifest[T]) = m def classManifest[T](implicit m: ClassManifest[T]) = m diff --git a/src/library/scala/collection/mutable/WrappedArray.scala b/src/library/scala/collection/mutable/WrappedArray.scala index 5e20f4ec61..9d170b2832 100644 --- a/src/library/scala/collection/mutable/WrappedArray.scala +++ b/src/library/scala/collection/mutable/WrappedArray.scala @@ -45,7 +45,7 @@ extends AbstractSeq[T] def elemTag: ArrayTag[T] @deprecated("use elemTag instead", "2.10.0") - def elemManifest: ClassManifest[T] = ClassManifest[T](arrayElementClass(elemTag)) + def elemManifest: ClassManifest[T] = ClassManifest.fromClass[T](arrayElementClass(elemTag).asInstanceOf[Class[T]]) /** The length of the array */ def length: Int diff --git a/src/library/scala/reflect/ClassManifest.scala b/src/library/scala/reflect/ClassManifest.scala new file mode 100644 index 0000000000..43e043fd40 --- /dev/null +++ b/src/library/scala/reflect/ClassManifest.scala @@ -0,0 +1,242 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2007-2011, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.reflect + +import scala.collection.mutable.{ WrappedArray, ArrayBuilder } +import java.lang.{ Class => jClass } + +/** A `ClassManifest[T]` is an opaque descriptor for type `T`. + * It is used by the compiler to preserve information necessary + * for instantiating `Arrays` in those cases where the element type + * is unknown at compile time. + * + * The type-relation operators make an effort to present a more accurate + * picture than can be realized with erased types, but they should not be + * relied upon to give correct answers. In particular they are likely to + * be wrong when variance is involved or when a subtype has a different + * number of type arguments than a supertype. + */ +@deprecated("Use `@scala.reflect.ClassTag` instead", "2.10.0") +trait ClassManifest[T] extends OptManifest[T] with ClassTag[T] with Equals with Serializable { + /** A class representing the type `U` to which `T` would be erased. Note + * that there is no subtyping relationship between `T` and `U`. */ + def erasure: jClass[_] + + private def subtype(sub: jClass[_], sup: jClass[_]): Boolean = { + def loop(left: Set[jClass[_]], seen: Set[jClass[_]]): Boolean = { + left.nonEmpty && { + val next = left.head + val supers = next.getInterfaces.toSet ++ Option(next.getSuperclass) + supers(sup) || { + val xs = left ++ supers filterNot seen + loop(xs - next, seen + next) + } + } + } + loop(Set(sub), Set()) + } + + private def subargs(args1: List[OptManifest[_]], args2: List[OptManifest[_]]) = (args1 corresponds args2) { + // !!! [Martin] this is wrong, need to take variance into account + case (x: ClassManifest[_], y: ClassManifest[_]) => x <:< y + case (x, y) => (x eq NoManifest) && (y eq NoManifest) + } + + /** Tests whether the type represented by this manifest is a subtype + * of the type represented by `that` manifest, subject to the limitations + * described in the header. + */ + def <:<(that: ClassManifest[_]): Boolean = { + // All types which could conform to these types will override <:<. + def cannotMatch = { + import Manifest._ + that.isInstanceOf[AnyValManifest[_]] || (that eq AnyVal) || (that eq Nothing) || (that eq Null) + } + + // This is wrong, and I don't know how it can be made right + // without more development of Manifests, due to arity-defying + // relationships like: + // + // List[String] <: AnyRef + // Map[Int, Int] <: Iterable[(Int, Int)] + // + // Given the manifest for Map[A, B] how do I determine that a + // supertype has single type argument (A, B) ? I don't see how we + // can say whether X <:< Y when type arguments are involved except + // when the erasure is the same, even before considering variance. + !cannotMatch && { + // this part is wrong for not considering variance + if (this.erasure == that.erasure) + subargs(this.typeArguments, that.typeArguments) + // this part is wrong for punting unless the rhs has no type + // arguments, but it's better than a blindfolded pinata swing. + else + that.typeArguments.isEmpty && subtype(this.erasure, that.erasure) + } + } + + /** Tests whether the type represented by this manifest is a supertype + * of the type represented by `that` manifest, subject to the limitations + * described in the header. + */ + def >:>(that: ClassManifest[_]): Boolean = + that <:< this + + override def canEqual(other: Any) = other match { + case _: ClassManifest[_] => true + case _ => false + } + + /** Tests whether the type represented by this manifest is equal to + * the type represented by `that` manifest, subject to the limitations + * described in the header. + */ + override def equals(that: Any): Boolean = that match { + case m: ClassManifest[_] => (m canEqual this) && (this.erasure == m.erasure) + case _ => false + } + override def hashCode = this.erasure.## + + protected def arrayClass[T](tp: jClass[_]): jClass[Array[T]] = + java.lang.reflect.Array.newInstance(tp, 0).getClass.asInstanceOf[jClass[Array[T]]] + + def arrayManifest: ClassManifest[Array[T]] = + ClassManifest.classType[Array[T]](arrayClass[T](erasure), this) + + override def newArray(len: Int): Array[T] = + java.lang.reflect.Array.newInstance(erasure, len).asInstanceOf[Array[T]] + + def newArray2(len: Int): Array[Array[T]] = + java.lang.reflect.Array.newInstance(arrayClass[T](erasure), len) + .asInstanceOf[Array[Array[T]]] + + def newArray3(len: Int): Array[Array[Array[T]]] = + java.lang.reflect.Array.newInstance(arrayClass[Array[T]](arrayClass[T](erasure)), len) + .asInstanceOf[Array[Array[Array[T]]]] + + def newArray4(len: Int): Array[Array[Array[Array[T]]]] = + java.lang.reflect.Array.newInstance(arrayClass[Array[Array[T]]](arrayClass[Array[T]](arrayClass[T](erasure))), len) + .asInstanceOf[Array[Array[Array[Array[T]]]]] + + def newArray5(len: Int): Array[Array[Array[Array[Array[T]]]]] = + java.lang.reflect.Array.newInstance(arrayClass[Array[Array[Array[T]]]](arrayClass[Array[Array[T]]](arrayClass[Array[T]](arrayClass[T](erasure)))), len) + .asInstanceOf[Array[Array[Array[Array[Array[T]]]]]] + + def newWrappedArray(len: Int): WrappedArray[T] = + // it's safe to assume T <: AnyRef here because the method is overridden for all value type manifests + new WrappedArray.ofRef[T with AnyRef](newArray(len).asInstanceOf[Array[T with AnyRef]]).asInstanceOf[WrappedArray[T]] + + def newArrayBuilder(): ArrayBuilder[T] = + // it's safe to assume T <: AnyRef here because the method is overridden for all value type manifests + new ArrayBuilder.ofRef[T with AnyRef]()(this.asInstanceOf[ClassManifest[T with AnyRef]]).asInstanceOf[ArrayBuilder[T]] + + def typeArguments: List[OptManifest[_]] = List() + + protected def argString = + if (typeArguments.nonEmpty) typeArguments.mkString("[", ", ", "]") + else if (erasure.isArray) "["+ClassManifest.fromClass(erasure.getComponentType)+"]" + else "" +} + +/** The object `ClassManifest` defines factory methods for manifests. + * It is intended for use by the compiler and should not be used in client code. + */ +@deprecated("Use `@scala.reflect.ClassTag` instead", "2.10.0") +object ClassManifest { + val Byte = Manifest.Byte + val Short = Manifest.Short + val Char = Manifest.Char + val Int = Manifest.Int + val Long = Manifest.Long + val Float = Manifest.Float + val Double = Manifest.Double + val Boolean = Manifest.Boolean + val Unit = Manifest.Unit + val Any = Manifest.Any + val Object = Manifest.Object + val AnyVal = Manifest.AnyVal + val Nothing = Manifest.Nothing + val Null = Manifest.Null + + def fromClass[T](clazz: jClass[T]): ClassManifest[T] = clazz match { + case java.lang.Byte.TYPE => Byte.asInstanceOf[ClassManifest[T]] + case java.lang.Short.TYPE => Short.asInstanceOf[ClassManifest[T]] + case java.lang.Character.TYPE => Char.asInstanceOf[ClassManifest[T]] + case java.lang.Integer.TYPE => Int.asInstanceOf[ClassManifest[T]] + case java.lang.Long.TYPE => Long.asInstanceOf[ClassManifest[T]] + case java.lang.Float.TYPE => Float.asInstanceOf[ClassManifest[T]] + case java.lang.Double.TYPE => Double.asInstanceOf[ClassManifest[T]] + case java.lang.Boolean.TYPE => Boolean.asInstanceOf[ClassManifest[T]] + case java.lang.Void.TYPE => Unit.asInstanceOf[ClassManifest[T]] + case _ => classType[T with AnyRef](clazz).asInstanceOf[ClassManifest[T]] + } + + def singleType[T <: AnyRef](value: AnyRef): Manifest[T] = Manifest.singleType(value) + + /** 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) + */ + def classType[T <: AnyRef](clazz: jClass[_]): ClassManifest[T] = + new ClassTypeManifest[T](None, clazz, Nil) + + /** ClassManifest for the class type `clazz[args]`, where `clazz` is + * a top-level or static class and `args` are its type arguments */ + def classType[T <: AnyRef](clazz: jClass[_], arg1: OptManifest[_], args: OptManifest[_]*): ClassManifest[T] = + new ClassTypeManifest[T](None, clazz, arg1 :: args.toList) + + /** ClassManifest for the class type `clazz[args]`, where `clazz` is + * a class with non-package prefix type `prefix` and type arguments `args`. + */ + def classType[T <: AnyRef](prefix: OptManifest[_], clazz: jClass[_], args: OptManifest[_]*): ClassManifest[T] = + new ClassTypeManifest[T](Some(prefix), clazz, args.toList) + + def arrayType[T](arg: OptManifest[_]): ClassManifest[Array[T]] = arg match { + case NoManifest => Object.asInstanceOf[ClassManifest[Array[T]]] + case m: ClassManifest[_] => m.asInstanceOf[ClassManifest[T]].arrayManifest + } + + /** 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. */ + def abstractType[T](prefix: OptManifest[_], name: String, clazz: jClass[_], args: OptManifest[_]*): ClassManifest[T] = + new ClassManifest[T] { + def erasure = clazz + override val typeArguments = args.toList + override def toString = prefix.toString+"#"+name+argString + } + + /** 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 + */ + def abstractType[T](prefix: OptManifest[_], name: String, upperbound: ClassManifest[_], args: OptManifest[_]*): ClassManifest[T] = + new ClassManifest[T] { + def erasure = upperbound.erasure + override val typeArguments = args.toList + override def toString = prefix.toString+"#"+name+argString + } +} + +/** Manifest for the class type `clazz[args]`, where `clazz` is + * a top-level or static class */ +private class ClassTypeManifest[T <: AnyRef]( + prefix: Option[OptManifest[_]], + val erasure: jClass[_], + override val typeArguments: List[OptManifest[_]]) extends ClassManifest[T] +{ + override def toString = + (if (prefix.isEmpty) "" else prefix.get.toString+"#") + + (if (erasure.isArray) "Array" else erasure.getName) + + argString +} \ No newline at end of file diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala new file mode 100644 index 0000000000..da029f046d --- /dev/null +++ b/src/library/scala/reflect/Manifest.scala @@ -0,0 +1,259 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2007-2011, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.reflect + +import scala.collection.mutable.{ ArrayBuilder, WrappedArray } +import mirror._ + +/** A `Manifest[T]` is an opaque descriptor for type T. Its supported use + * is to give access to the erasure of the type as a `Class` instance, as + * is necessary for the creation of native `Arrays` if the class is not + * known at compile time. + * + * The type-relation operators `<:<` and `=:=` should be considered + * approximations only, as there are numerous aspects of type conformance + * which are not yet adequately represented in manifests. + * + * Example usages: +{{{ + def arr[T] = new Array[T](0) // does not compile + def arr[T](implicit m: Manifest[T]) = new Array[T](0) // compiles + def arr[T: Manifest] = new Array[T](0) // shorthand for the preceding + + // Methods manifest, classManifest, and optManifest are in [[scala.Predef]]. + def isApproxSubType[T: Manifest, U: Manifest] = manifest[T] <:< manifest[U] + isApproxSubType[List[String], List[AnyRef]] // true + isApproxSubType[List[String], List[Int]] // false + + def methods[T: ClassManifest] = classManifest[T].erasure.getMethods + def retType[T: ClassManifest](name: String) = + methods[T] find (_.getName == name) map (_.getGenericReturnType) + + retType[Map[_, _]]("values") // Some(scala.collection.Iterable) +}}} + * + */ +@annotation.implicitNotFound(msg = "No Manifest available for ${T}.") +@deprecated("Use `@scala.reflect.ConcreteTypeTag` instead", "2.10.0") +trait Manifest[T] extends ClassManifest[T] with Equals { + override def typeArguments: List[Manifest[_]] = Nil + + override def arrayManifest: Manifest[Array[T]] = + Manifest.classType[Array[T]](arrayClass[T](erasure), this) + + override def canEqual(that: Any): Boolean = that match { + case _: Manifest[_] => true + case _ => false + } + /** Note: testing for erasure here is important, as it is many times + * faster than <:< and rules out most comparisons. + */ + override def equals(that: Any): Boolean = that match { + case m: Manifest[_] => (m canEqual this) && (this.erasure == m.erasure) && (this <:< m) && (m <:< this) + case _ => false + } + override def hashCode = this.erasure.## +} + +@deprecated("Use type tags and manually check the corresponding class or type instead", "2.10.0") +abstract class AnyValManifest[T <: AnyVal](override val toString: String) extends Manifest[T] with Equals { + override def <:<(that: ClassManifest[_]): Boolean = + (that eq this) || (that eq Manifest.Any) || (that eq Manifest.AnyVal) + override def canEqual(other: Any) = other match { + case _: AnyValManifest[_] => true + case _ => false + } + override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] + override val hashCode = System.identityHashCode(this) +} + +/** The object `Manifest` defines factory methods for manifests. + * It is intended for use by the compiler and should not be used + * in client code. + */ +@deprecated("Use `@scala.reflect.ConcreteTypeTag` instead", "2.10.0") +object Manifest { + def valueManifests: List[AnyValManifest[_]] = + List(Byte, Short, Char, Int, Long, Float, Double, Boolean, Unit) + + val Byte: AnyValManifest[Byte] = new AnyValManifest[scala.Byte]("Byte") { + def erasure = java.lang.Byte.TYPE + override def newArray(len: Int): Array[Byte] = new Array[Byte](len) + override def newWrappedArray(len: Int): WrappedArray[Byte] = new WrappedArray.ofByte(new Array[Byte](len)) + override def newArrayBuilder(): ArrayBuilder[Byte] = new ArrayBuilder.ofByte() + private def readResolve(): Any = Manifest.Byte + } + + val Short: AnyValManifest[Short] = new AnyValManifest[scala.Short]("Short") { + def erasure = java.lang.Short.TYPE + override def newArray(len: Int): Array[Short] = new Array[Short](len) + override def newWrappedArray(len: Int): WrappedArray[Short] = new WrappedArray.ofShort(new Array[Short](len)) + override def newArrayBuilder(): ArrayBuilder[Short] = new ArrayBuilder.ofShort() + private def readResolve(): Any = Manifest.Short + } + + val Char: AnyValManifest[Char] = new AnyValManifest[scala.Char]("Char") { + def erasure = java.lang.Character.TYPE + override def newArray(len: Int): Array[Char] = new Array[Char](len) + override def newWrappedArray(len: Int): WrappedArray[Char] = new WrappedArray.ofChar(new Array[Char](len)) + override def newArrayBuilder(): ArrayBuilder[Char] = new ArrayBuilder.ofChar() + private def readResolve(): Any = Manifest.Char + } + + val Int: AnyValManifest[Int] = new AnyValManifest[scala.Int]("Int") { + def erasure = java.lang.Integer.TYPE + override def newArray(len: Int): Array[Int] = new Array[Int](len) + override def newWrappedArray(len: Int): WrappedArray[Int] = new WrappedArray.ofInt(new Array[Int](len)) + override def newArrayBuilder(): ArrayBuilder[Int] = new ArrayBuilder.ofInt() + private def readResolve(): Any = Manifest.Int + } + + val Long: AnyValManifest[Long] = new AnyValManifest[scala.Long]("Long") { + def erasure = java.lang.Long.TYPE + override def newArray(len: Int): Array[Long] = new Array[Long](len) + override def newWrappedArray(len: Int): WrappedArray[Long] = new WrappedArray.ofLong(new Array[Long](len)) + override def newArrayBuilder(): ArrayBuilder[Long] = new ArrayBuilder.ofLong() + private def readResolve(): Any = Manifest.Long + } + + val Float: AnyValManifest[Float] = new AnyValManifest[scala.Float]("Float") { + def erasure = java.lang.Float.TYPE + override def newArray(len: Int): Array[Float] = new Array[Float](len) + override def newWrappedArray(len: Int): WrappedArray[Float] = new WrappedArray.ofFloat(new Array[Float](len)) + override def newArrayBuilder(): ArrayBuilder[Float] = new ArrayBuilder.ofFloat() + private def readResolve(): Any = Manifest.Float + } + + val Double: AnyValManifest[Double] = new AnyValManifest[scala.Double]("Double") { + def erasure = java.lang.Double.TYPE + override def newArray(len: Int): Array[Double] = new Array[Double](len) + override def newWrappedArray(len: Int): WrappedArray[Double] = new WrappedArray.ofDouble(new Array[Double](len)) + override def newArrayBuilder(): ArrayBuilder[Double] = new ArrayBuilder.ofDouble() + private def readResolve(): Any = Manifest.Double + } + + val Boolean: AnyValManifest[Boolean] = new AnyValManifest[scala.Boolean]("Boolean") { + def erasure = java.lang.Boolean.TYPE + override def newArray(len: Int): Array[Boolean] = new Array[Boolean](len) + override def newWrappedArray(len: Int): WrappedArray[Boolean] = new WrappedArray.ofBoolean(new Array[Boolean](len)) + override def newArrayBuilder(): ArrayBuilder[Boolean] = new ArrayBuilder.ofBoolean() + private def readResolve(): Any = Manifest.Boolean + } + + val Unit: AnyValManifest[Unit] = new AnyValManifest[scala.Unit]("Unit") { + def erasure = java.lang.Void.TYPE + override def newArray(len: Int): Array[Unit] = new Array[Unit](len) + override def newWrappedArray(len: Int): WrappedArray[Unit] = new WrappedArray.ofUnit(new Array[Unit](len)) + override def newArrayBuilder(): ArrayBuilder[Unit] = new ArrayBuilder.ofUnit() + private def readResolve(): Any = Manifest.Unit + } + + val Any: Manifest[scala.Any] = new PhantomManifest[scala.Any]("Any") { + override def <:<(that: ClassManifest[_]): Boolean = (that eq this) + private def readResolve(): Any = Manifest.Any + } + + val Object: Manifest[java.lang.Object] = new PhantomManifest[java.lang.Object]("Object") { + override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) + private def readResolve(): Any = Manifest.Object + } + + val AnyVal: Manifest[scala.AnyVal] = new PhantomManifest[scala.AnyVal]("AnyVal") { + override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) + private def readResolve(): Any = Manifest.AnyVal + } + + val Null: Manifest[scala.Null] = new PhantomManifest[scala.Null]("Null") { + override def <:<(that: ClassManifest[_]): Boolean = + (that ne null) && (that ne Nothing) && !(that <:< AnyVal) + private def readResolve(): Any = Manifest.Null + } + + val Nothing: Manifest[scala.Nothing] = new PhantomManifest[scala.Nothing]("Nothing") { + override def <:<(that: ClassManifest[_]): Boolean = (that ne null) + private def readResolve(): Any = Manifest.Nothing + } + + private class SingletonTypeManifest[T <: AnyRef](value: AnyRef) extends Manifest[T] { + lazy val erasure = value.getClass + override lazy val toString = value.toString + ".type" + } + + /** Manifest for the singleton type `value.type`. */ + def singleType[T <: AnyRef](value: AnyRef): Manifest[T] = + new SingletonTypeManifest[T](value) + + /** 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) + */ + def classType[T](clazz: Predef.Class[_]): Manifest[T] = + new ClassTypeManifest[T](None, clazz, Nil) + + /** Manifest for the class type `clazz`, where `clazz` is + * a top-level or static class and args are its type arguments. */ + def classType[T](clazz: Predef.Class[T], arg1: Manifest[_], args: Manifest[_]*): Manifest[T] = + new ClassTypeManifest[T](None, clazz, arg1 :: args.toList) + + /** Manifest for the class type `clazz[args]`, where `clazz` is + * a class with non-package prefix type `prefix` and type arguments `args`. + */ + def classType[T](prefix: Manifest[_], clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] = + new ClassTypeManifest[T](Some(prefix), clazz, args.toList) + + private abstract class PhantomManifest[T](override val toString: String) extends ClassTypeManifest[T](None, classOf[java.lang.Object], Nil) { + override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] + override val hashCode = System.identityHashCode(this) + } + + /** Manifest for the class type `clazz[args]`, where `clazz` is + * a top-level or static class. */ + private class ClassTypeManifest[T](prefix: Option[Manifest[_]], + val erasure: Predef.Class[_], + override val typeArguments: List[Manifest[_]]) extends Manifest[T] { + override def toString = + (if (prefix.isEmpty) "" else prefix.get.toString+"#") + + (if (erasure.isArray) "Array" else erasure.getName) + + argString + } + + def arrayType[T](arg: Manifest[_]): Manifest[Array[T]] = + arg.asInstanceOf[Manifest[T]].arrayManifest + + /** 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. */ + def abstractType[T](prefix: Manifest[_], name: String, upperBound: Predef.Class[_], args: Manifest[_]*): Manifest[T] = + new Manifest[T] { + def erasure = upperBound + override val typeArguments = args.toList + override def toString = prefix.toString+"#"+name+argString + } + + /** Manifest for the unknown type `_ >: L <: U` in an existential. + */ + def wildcardType[T](lowerBound: Manifest[_], upperBound: Manifest[_]): Manifest[T] = + new Manifest[T] { + def erasure = upperBound.erasure + override def toString = + "_" + + (if (lowerBound eq Nothing) "" else " >: "+lowerBound) + + (if (upperBound eq Nothing) "" else " <: "+upperBound) + } + + /** Manifest for the intersection type `parents_0 with ... with parents_n'. */ + def intersectionType[T](parents: Manifest[_]*): Manifest[T] = + new Manifest[T] { + def erasure = parents.head.erasure + override def toString = parents.mkString(" with ") + } +} \ No newline at end of file diff --git a/src/library/scala/reflect/NoManifest.scala b/src/library/scala/reflect/NoManifest.scala new file mode 100644 index 0000000000..7b8037272c --- /dev/null +++ b/src/library/scala/reflect/NoManifest.scala @@ -0,0 +1,16 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2007-2011, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.reflect + +/** One of the branches of an [[scala.reflect.OptManifest]]. + */ +@deprecated("Use `@scala.reflect.TypeTag` instead", "2.10.0") +object NoManifest extends OptManifest[Nothing] with Serializable { + override def toString = "" +} \ No newline at end of file diff --git a/src/library/scala/reflect/OptManifest.scala b/src/library/scala/reflect/OptManifest.scala new file mode 100644 index 0000000000..46f23c4e22 --- /dev/null +++ b/src/library/scala/reflect/OptManifest.scala @@ -0,0 +1,18 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2007-2011, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.reflect + +/** A `OptManifest[T]` is an optional [[scala.reflect.Manifest]]. + * + * It is either a `Manifest` or the value `NoManifest`. + * + * @author Martin Odersky + */ +@deprecated("Use `@scala.reflect.TypeTag` instead", "2.10.0") +trait OptManifest[+T] extends Serializable \ No newline at end of file diff --git a/src/library/scala/reflect/package.scala b/src/library/scala/reflect/package.scala index 640cad6c21..0e6350183f 100644 --- a/src/library/scala/reflect/package.scala +++ b/src/library/scala/reflect/package.scala @@ -53,20 +53,6 @@ package object reflect { @deprecated("Use `@scala.beans.ScalaBeanInfo` instead", "2.10.0") type ScalaBeanInfo = scala.beans.ScalaBeanInfo - @deprecated("Use `@scala.reflect.ClassTag` instead", "2.10.0") - type ClassManifest[T] = ClassTag[T] - @deprecated("OptManifest is no longer supported, and using it may lead to incorrect results, Use `@scala.reflect.TypeTag` instead", "2.10.0") - type OptManifest[T] = TypeTag[T] - @deprecated("Use `@scala.reflect.ConcreteTypeTag` instead", "2.10.0") - type Manifest[T] = ConcreteTypeTag[T] - - @deprecated("Use `@scala.reflect.ClassTag` instead", "2.10.0") - val ClassManifest = ClassTag - @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") - 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 -- cgit v1.2.3