summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-12-09 17:03:48 +0000
committerPaul Phillips <paulp@improving.org>2009-12-09 17:03:48 +0000
commita4f1bfec2c2e1067964fad4868ae701374ab1ccd (patch)
tree932a770e73b585afd4dd6a9f783bc9c4671cdfc5
parent8bd78809c494666cb49904458c09f256b27a9e2f (diff)
downloadscala-a4f1bfec2c2e1067964fad4868ae701374ab1ccd.tar.gz
scala-a4f1bfec2c2e1067964fad4868ae701374ab1ccd.tar.bz2
scala-a4f1bfec2c2e1067964fad4868ae701374ab1ccd.zip
Took manifests a little closer to the finish line.
doesn't work but the relationships between all the top, nearly top, and bottom types should all be all correct. (See lengthy test case.)
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala30
-rw-r--r--src/library/scala/reflect/ClassManifest.scala19
-rw-r--r--src/library/scala/reflect/Manifest.scala53
-rw-r--r--test/files/run/manifests.scala147
4 files changed, 211 insertions, 38 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index bb7f99f222..2bd296b65d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -724,16 +724,20 @@ self: Analyzer =>
/** 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
- typed { atPos(tree.pos.focus) {
- Apply(
- TypeApply(
- Select(gen.mkAttributedRef(if (full) FullManifestModule else PartialManifestModule), constructor),
- List(TypeTree(tparg))
- ),
- args.toList
- )
- }}
+ else typedPos(tree.pos.focus) {
+ Apply(
+ TypeApply(
+ Select(gen.mkAttributedRef(if (full) FullManifestModule else PartialManifestModule), constructor),
+ List(TypeTree(tparg))
+ ),
+ args.toList
+ )
+ }
+
+ /** 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) =
@@ -750,9 +754,9 @@ self: Analyzer =>
manifestOfType(tp1.deconst, full)
case TypeRef(pre, sym, args) =>
if (isValueClass(sym) || isPhantomClass(sym)) {
- typed { atPos(tree.pos.focus) {
- Select(gen.mkAttributedRef(FullManifestModule), sym.name.toString)
- }}
+ findSingletonManifest(sym.name.toString)
+ } else if (sym == ObjectClass || sym == AnyRefClass) {
+ findSingletonManifest("Object")
} else if (sym == ArrayClass && args.length == 1) {
manifestFactoryCall("arrayType", args.head, findSubManifest(args.head))
} else if (sym.isClass) {
diff --git a/src/library/scala/reflect/ClassManifest.scala b/src/library/scala/reflect/ClassManifest.scala
index dd15e2f8b8..81c36fffcb 100644
--- a/src/library/scala/reflect/ClassManifest.scala
+++ b/src/library/scala/reflect/ClassManifest.scala
@@ -52,8 +52,18 @@ trait ClassManifest[T] extends OptManifest[T] {
case _ => false
}
}
- (this.erasure == that.erasure || subtype(this.erasure, that.erasure)) &&
- subargs(this.typeArguments, that.typeArguments)
+
+ import Manifest.{ AnyVal, Nothing, Null }
+
+ that match {
+ // All types which conform to AnyVal will override <:<.
+ case _: AnyValManifest[_] => false
+ // Anything which conforms to a bottom type will override <:<.
+ case AnyVal | Nothing | Null => false
+ case _ =>
+ (this.erasure == that.erasure || subtype(this.erasure, that.erasure)) &&
+ subargs(this.typeArguments, that.typeArguments)
+ }
}
/** Tests whether the type represented by this manifest is a supertype
@@ -68,7 +78,8 @@ trait ClassManifest[T] extends OptManifest[T] {
* implementation is an approximation, as the test is done on the
* erasure of the type. */
override def equals(that: Any): Boolean = that match {
- case m: ClassManifest[_] => this.erasure == m.erasure
+ case _: AnyValManifest[_] => false
+ case m: ClassManifest[_] => this.erasure == m.erasure
case _ => false
}
@@ -153,7 +164,7 @@ object ClassManifest {
case _ => classType[T with AnyRef](clazz).asInstanceOf[ClassManifest[T]]
}
- def singleType[T](value: Any): Manifest[T] = Manifest.singleType(value)
+ 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.
diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala
index f7ed9b4be9..71324a9802 100644
--- a/src/library/scala/reflect/Manifest.scala
+++ b/src/library/scala/reflect/Manifest.scala
@@ -34,6 +34,13 @@ trait Manifest[T] extends ClassManifest[T] {
Manifest.classType[Array[T]](arrayClass[T](erasure))
}
+@serializable
+trait AnyValManifest[T] extends Manifest[T] {
+ import Manifest.{ Any, AnyVal }
+ override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) || (that eq AnyVal)
+ override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef]
+}
+
/** <ps>
* This object is used by the compiler and <b>should not be used in client
* code</b>. The object <code>Manifest</code> defines factory methods for
@@ -45,8 +52,7 @@ trait Manifest[T] extends ClassManifest[T] {
* </p>
*/
object Manifest {
-
- val Byte = new (Manifest[Byte] @serializable) {
+ val Byte = new (AnyValManifest[Byte] @serializable) {
def erasure = java.lang.Byte.TYPE
override def toString = "Byte"
override def newArray(len: Int): Array[Byte] = new Array[Byte](len)
@@ -54,7 +60,7 @@ object Manifest {
override def newArrayBuilder(): ArrayBuilder[Byte] = new ArrayBuilder.ofByte()
}
- val Short = new (Manifest[Short] @serializable) {
+ val Short = new (AnyValManifest[Short] @serializable) {
def erasure = java.lang.Short.TYPE
override def toString = "Short"
override def newArray(len: Int): Array[Short] = new Array[Short](len)
@@ -62,7 +68,7 @@ object Manifest {
override def newArrayBuilder(): ArrayBuilder[Short] = new ArrayBuilder.ofShort()
}
- val Char = new (Manifest[Char] @serializable) {
+ val Char = new (AnyValManifest[Char] @serializable) {
def erasure = java.lang.Character.TYPE
override def toString = "Char"
override def newArray(len: Int): Array[Char] = new Array[Char](len)
@@ -70,7 +76,7 @@ object Manifest {
override def newArrayBuilder(): ArrayBuilder[Char] = new ArrayBuilder.ofChar()
}
- val Int = new (Manifest[Int] @serializable) {
+ val Int = new (AnyValManifest[Int] @serializable) {
def erasure = java.lang.Integer.TYPE
override def toString = "Int"
override def newArray(len: Int): Array[Int] = new Array[Int](len)
@@ -78,7 +84,7 @@ object Manifest {
override def newArrayBuilder(): ArrayBuilder[Int] = new ArrayBuilder.ofInt()
}
- val Long = new (Manifest[Long] @serializable) {
+ val Long = new (AnyValManifest[Long] @serializable) {
def erasure = java.lang.Long.TYPE
override def toString = "Long"
override def newArray(len: Int): Array[Long] = new Array[Long](len)
@@ -86,7 +92,7 @@ object Manifest {
override def newArrayBuilder(): ArrayBuilder[Long] = new ArrayBuilder.ofLong()
}
- val Float = new (Manifest[Float] @serializable) {
+ val Float = new (AnyValManifest[Float] @serializable) {
def erasure = java.lang.Float.TYPE
override def toString = "Float"
override def newArray(len: Int): Array[Float] = new Array[Float](len)
@@ -94,7 +100,7 @@ object Manifest {
override def newArrayBuilder(): ArrayBuilder[Float] = new ArrayBuilder.ofFloat()
}
- val Double = new (Manifest[Double] @serializable) {
+ val Double = new (AnyValManifest[Double] @serializable) {
def erasure = java.lang.Double.TYPE
override def toString = "Double"
override def newArray(len: Int): Array[Double] = new Array[Double](len)
@@ -102,7 +108,7 @@ object Manifest {
override def newArrayBuilder(): ArrayBuilder[Double] = new ArrayBuilder.ofDouble()
}
- val Boolean = new (Manifest[Boolean] @serializable) {
+ val Boolean = new (AnyValManifest[Boolean] @serializable) {
def erasure = java.lang.Boolean.TYPE
override def toString = "Boolean"
override def newArray(len: Int): Array[Boolean] = new Array[Boolean](len)
@@ -110,7 +116,7 @@ object Manifest {
override def newArrayBuilder(): ArrayBuilder[Boolean] = new ArrayBuilder.ofBoolean()
}
- val Unit = new (Manifest[Unit] @serializable) {
+ val Unit = new (AnyValManifest[Unit] @serializable) {
def erasure = java.lang.Void.TYPE
override def toString = "Unit"
override def newArray(len: Int): Array[Unit] = new Array[Unit](len)
@@ -120,37 +126,42 @@ object Manifest {
val Any: Manifest[Any] = new ClassTypeManifest[Any](None, classOf[java.lang.Object], List()) {
override def toString = "Any"
- // todo: re-implement <:<
+ override def <:<(that: ClassManifest[_]): Boolean = (that eq this)
+ override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef]
}
val Object: Manifest[Object] = new ClassTypeManifest[Object](None, classOf[java.lang.Object], List()) {
override def toString = "Object"
- // todo: re-implement <:<
+ override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any)
+ override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef]
}
val AnyVal: Manifest[AnyVal] = new ClassTypeManifest[AnyVal](None, classOf[java.lang.Object], List()) {
override def toString = "AnyVal"
- // todo: re-implement <:<
+ override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any)
+ override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef]
}
val Null: Manifest[Null] = new ClassTypeManifest[Null](None, classOf[java.lang.Object], List()) {
override def toString = "Null"
- // todo: re-implement <:<
+ override def <:<(that: ClassManifest[_]): Boolean =
+ (that ne null) && (that ne Nothing) && !(that <:< AnyVal)
+ override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef]
}
val Nothing: Manifest[Nothing] = new ClassTypeManifest[Nothing](None, classOf[java.lang.Object], List()) {
override def toString = "Nothing"
- // todo: re-implement <:<
+ override def <:<(that: ClassManifest[_]): Boolean = (that ne null)
+ override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef]
}
/** Manifest for the singleton type `value.type'. */
- def singleType[T](value: Any): Manifest[T] =
+ def singleType[T <: AnyRef](value: AnyRef): Manifest[T] =
new (Manifest[T] @serializable) {
- lazy val erasure =
- value match {
- case anyRefValue: AnyRef => anyRefValue.getClass
- case anyValue => error("There is no singleton type for AnyVal values")
- }
+ /** Note - this was doing a type match on value to exclude AnyVal, which does not work.
+ * Pattern matching _: AnyRef matches everything because of boxing.
+ */
+ lazy val erasure = value.getClass
override lazy val toString = value.toString + ".type"
}
diff --git a/test/files/run/manifests.scala b/test/files/run/manifests.scala
new file mode 100644
index 0000000000..ed6efab70d
--- /dev/null
+++ b/test/files/run/manifests.scala
@@ -0,0 +1,147 @@
+object Test
+{
+ object Variances extends Enumeration {
+ val CO, IN, CONTRA = Value
+ }
+ import Variances.{ CO, IN, CONTRA }
+
+ object SubtypeRelationship extends Enumeration {
+ val NONE, SAME, SUB, SUPER = Value
+ }
+ import SubtypeRelationship.{ NONE, SAME, SUB, SUPER }
+
+ class VarianceTester[T, U, CC[_]](expected: Variances.Value)(
+ implicit ev1: Manifest[T], ev2: Manifest[U], ev3: Manifest[CC[T]], ev4: Manifest[CC[U]]) {
+
+ def elements = List(ev1 <:< ev2, ev2 <:< ev1)
+ def containers = List(ev3 <:< ev4, ev4 <:< ev3)
+
+ def isUnrelated = typeCompare[T, U] == NONE
+ def isSame = typeCompare[T, U] == SAME
+ def isSub = typeCompare[T, U] == SUB
+ def isSuper = typeCompare[T, U] == SUPER
+
+ def showsCovariance = (elements == containers)
+ def showsContravariance = (elements == containers.reverse)
+ def showsInvariance = containers forall (_ == isSame)
+
+ def allContainerVariances = List(showsCovariance, showsInvariance, showsContravariance)
+
+ def showsExpectedVariance =
+ if (isUnrelated) allContainerVariances forall (_ == false)
+ else if (isSame) allContainerVariances forall (_ == true)
+ else expected match {
+ case CO => showsCovariance && !showsContravariance && !showsInvariance
+ case IN => showsInvariance && !showsCovariance && !showsContravariance
+ case CONTRA => showsContravariance && !showsCovariance && !showsInvariance
+ }
+ }
+
+ def showsCovariance[T, U, CC[_]](implicit ev1: Manifest[T], ev2: Manifest[U], ev3: Manifest[CC[T]], ev4: Manifest[CC[U]]) =
+ new VarianceTester[T, U, CC](CO) showsExpectedVariance
+
+ def showsInvariance[T, U, CC[_]](implicit ev1: Manifest[T], ev2: Manifest[U], ev3: Manifest[CC[T]], ev4: Manifest[CC[U]]) =
+ new VarianceTester[T, U, CC](IN) showsExpectedVariance
+
+ def showsContravariance[T, U, CC[_]](implicit ev1: Manifest[T], ev2: Manifest[U], ev3: Manifest[CC[T]], ev4: Manifest[CC[U]]) =
+ new VarianceTester[T, U, CC](CONTRA) showsExpectedVariance
+
+ def typeCompare[T, U](implicit ev1: Manifest[T], ev2: Manifest[U]) = (ev1 <:< ev2, ev2 <:< ev1) match {
+ case (true, true) => SAME
+ case (true, false) => SUB
+ case (false, true) => SUPER
+ case (false, false) => NONE
+ }
+
+ def assertAnyRef[T: Manifest] = List(
+ manifest[T] <:< manifest[Any],
+ manifest[T] <:< manifest[AnyRef],
+ !(manifest[T] <:< manifest[AnyVal])
+ ) foreach (assert(_, "assertAnyRef"))
+
+ def assertAnyVal[T: Manifest] = List(
+ manifest[T] <:< manifest[Any],
+ !(manifest[T] <:< manifest[AnyRef]),
+ manifest[T] <:< manifest[AnyVal]
+ ) foreach (assert(_, "assertAnyVal"))
+
+ def assertSameType[T: Manifest, U: Manifest] = assert(typeCompare[T, U] == SAME, "assertSameType")
+ def assertSuperType[T: Manifest, U: Manifest] = assert(typeCompare[T, U] == SUPER, "assertSuperType")
+ def assertSubType[T: Manifest, U: Manifest] = assert(typeCompare[T, U] == SUB, "assertSubType")
+ def assertNoRelationship[T: Manifest, U: Manifest] = assert(typeCompare[T, U] == NONE, "assertNoRelationship")
+
+ def testVariancesVia[T: Manifest, U: Manifest] = assert(
+ typeCompare[T, U] == SUB &&
+ showsCovariance[T, U, List] &&
+ showsInvariance[T, U, Set],
+ "testVariancesVia"
+ )
+
+ def runAllTests = {
+ assertAnyVal[AnyVal]
+ assertAnyVal[Unit]
+ assertAnyVal[Int]
+ assertAnyVal[Double]
+ assertAnyVal[Boolean]
+ assertAnyVal[Char]
+
+ assertAnyRef[AnyRef]
+ assertAnyRef[java.lang.Object]
+ assertAnyRef[java.lang.Integer]
+ assertAnyRef[java.lang.Double]
+ assertAnyRef[java.lang.Boolean]
+ assertAnyRef[java.lang.Character]
+ assertAnyRef[String]
+ assertAnyRef[scala.List[String]]
+ assertAnyRef[scala.List[_]]
+
+ // variance doesn't work yet
+ // testVariancesVia[String, Any]
+ // testVariancesVia[String, AnyRef]
+
+ assertSubType[List[String], List[Any]]
+ assertSubType[List[String], List[AnyRef]]
+ assertNoRelationship[List[String], List[AnyVal]]
+
+ assertSubType[List[Int], List[Any]]
+ assertSubType[List[Int], List[AnyVal]]
+ assertNoRelationship[List[Int], List[AnyRef]]
+
+ // Nothing
+ assertSubType[Nothing, Any]
+ assertSubType[Nothing, AnyVal]
+ assertSubType[Nothing, AnyRef]
+ assertSubType[Nothing, String]
+ assertSubType[Nothing, List[String]]
+ assertSubType[Nothing, Null]
+ assertSameType[Nothing, Nothing]
+
+ // Null
+ assertSubType[Null, Any]
+ assertNoRelationship[Null, AnyVal]
+ assertSubType[Null, AnyRef]
+ assertSubType[Null, String]
+ assertSubType[Null, List[String]]
+ assertSameType[Null, Null]
+ assertSuperType[Null, Nothing]
+
+ // Any
+ assertSameType[Any, Any]
+ assertSuperType[Any, AnyVal]
+ assertSuperType[Any, AnyRef]
+ assertSuperType[Any, String]
+ assertSuperType[Any, List[String]]
+ assertSuperType[Any, Null]
+ assertSuperType[Any, Nothing]
+
+ // Misc unrelated types
+ assertNoRelationship[Unit, AnyRef]
+ assertNoRelationship[Unit, Int]
+ assertNoRelationship[Int, Long]
+ assertNoRelationship[Boolean, String]
+ assertNoRelationship[List[Boolean], List[String]]
+ assertNoRelationship[Set[Boolean], Set[String]]
+ }
+
+ def main(args: Array[String]): Unit = runAllTests
+}