diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Implicits.scala | 30 | ||||
-rw-r--r-- | src/library/scala/reflect/ClassManifest.scala | 19 | ||||
-rw-r--r-- | src/library/scala/reflect/Manifest.scala | 53 | ||||
-rw-r--r-- | test/files/run/manifests.scala | 147 |
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 +} |