diff options
-rw-r--r-- | src/library/scala/reflect/ClassTag.scala | 48 | ||||
-rw-r--r-- | test/files/run/t6318_primitives.check | 54 | ||||
-rw-r--r-- | test/files/run/t6318_primitives.scala | 40 | ||||
-rw-r--r-- | test/files/run/virtpatmat_typetag.check | 4 |
4 files changed, 96 insertions, 50 deletions
diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index 33c5cee783..bced505273 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -70,26 +70,36 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial * `SomeExtractor(...)` is turned into `ct(SomeExtractor(...))` if `T` in `SomeExtractor.unapply(x: T)` * is uncheckable, but we have an instance of `ClassTag[T]`. */ - def unapply(x: Any): Option[T] = unapply_impl(x) - def unapply(x: Byte): Option[T] = unapply_impl(x) - def unapply(x: Short): Option[T] = unapply_impl(x) - def unapply(x: Char): Option[T] = unapply_impl(x) - def unapply(x: Int): Option[T] = unapply_impl(x) - def unapply(x: Long): Option[T] = unapply_impl(x) - def unapply(x: Float): Option[T] = unapply_impl(x) - def unapply(x: Double): Option[T] = unapply_impl(x) - def unapply(x: Boolean): Option[T] = unapply_impl(x) - def unapply(x: Unit): Option[T] = unapply_impl(x) + def unapply(x: Any): Option[T] = x match { + case null => None + case b: Byte => unapply(b) + case s: Short => unapply(s) + case c: Char => unapply(c) + case i: Int => unapply(i) + case l: Long => unapply(l) + case f: Float => unapply(f) + case d: Double => unapply(d) + case b: Boolean => unapply(b) + case u: Unit => unapply(u) + case a: Any => unapplyImpl(a) + } - private def unapply_impl[U: ClassTag](x: U): Option[T] = - if (x == null) None - else { - val staticClass = classTag[U].runtimeClass - val dynamicClass = x.getClass - val effectiveClass = if (staticClass.isPrimitive) staticClass else dynamicClass - val conforms = runtimeClass.isAssignableFrom(effectiveClass) - if (conforms) Some(x.asInstanceOf[T]) else None - } + // TODO: Inline the bodies of these into the Any-accepting unapply overload above and delete them. + // This cannot be done until at least 2.12.0 for reasons of binary compatibility + def unapply(x: Byte) : Option[T] = unapplyImpl(x, classOf[Byte]) + def unapply(x: Short) : Option[T] = unapplyImpl(x, classOf[Short]) + def unapply(x: Char) : Option[T] = unapplyImpl(x, classOf[Char]) + def unapply(x: Int) : Option[T] = unapplyImpl(x, classOf[Int]) + def unapply(x: Long) : Option[T] = unapplyImpl(x, classOf[Long]) + def unapply(x: Float) : Option[T] = unapplyImpl(x, classOf[Float]) + def unapply(x: Double) : Option[T] = unapplyImpl(x, classOf[Double]) + def unapply(x: Boolean) : Option[T] = unapplyImpl(x, classOf[Boolean]) + def unapply(x: Unit) : Option[T] = unapplyImpl(x, classOf[Unit]) + + private[this] def unapplyImpl(x: Any, alternative: jClass[_] = null): Option[T] = { + val conforms = runtimeClass.isAssignableFrom(x.getClass) || (alternative != null && runtimeClass.isAssignableFrom(alternative)) + if (conforms) Some(x.asInstanceOf[T]) else None + } // case class accessories override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]] diff --git a/test/files/run/t6318_primitives.check b/test/files/run/t6318_primitives.check index b330f91276..4bc5e598eb 100644 --- a/test/files/run/t6318_primitives.check +++ b/test/files/run/t6318_primitives.check @@ -1,36 +1,54 @@ -true +Checking if byte matches byte Some(1) -false +Checking if byte matches short None -true +Checking if class java.lang.Byte matches byte Some(1) -false +Checking if short matches short +Some(1) +Checking if short matches char None -true +Checking if class java.lang.Short matches short +Some(1) +Checking if char matches char Some() -false +Checking if char matches int None -true +Checking if class java.lang.Character matches char +Some() +Checking if int matches int Some(1) -false +Checking if int matches long None -true +Checking if class java.lang.Integer matches int Some(1) -false +Checking if long matches long +Some(1) +Checking if long matches float None -true +Checking if class java.lang.Long matches long +Some(1) +Checking if float matches float Some(1.0) -false +Checking if float matches double None -true +Checking if class java.lang.Float matches float Some(1.0) -false +Checking if double matches double +Some(1.0) +Checking if double matches boolean None -true +Checking if class java.lang.Double matches double +Some(1.0) +Checking if boolean matches boolean Some(true) -false +Checking if boolean matches void None -true +Checking if class java.lang.Boolean matches boolean +Some(true) +Checking if void matches void Some(()) -false +Checking if void matches byte None +Checking if class scala.runtime.BoxedUnit matches void +Some(()) diff --git a/test/files/run/t6318_primitives.scala b/test/files/run/t6318_primitives.scala index 30f27120b3..bc8ec88359 100644 --- a/test/files/run/t6318_primitives.scala +++ b/test/files/run/t6318_primitives.scala @@ -2,70 +2,88 @@ import scala.reflect.{ClassTag, classTag} object Test extends App { def test[T: ClassTag](x: T) { - println(classTag[T].runtimeClass.isAssignableFrom(x.getClass)) + println(s"Checking if ${x.getClass} matches ${classTag[T].runtimeClass}") println(classTag[T].unapply(x)) } { val x = 1.toByte - println(ClassTag.Byte.runtimeClass.isAssignableFrom(x.getClass)) + println(s"Checking if ${x.getClass} matches ${classTag[Byte].runtimeClass}") println(ClassTag.Byte.unapply(x)) + println(s"Checking if ${x.getClass} matches ${classTag[Short].runtimeClass}") + println(ClassTag.Short.unapply(x)) test(x) } { val x = 1.toShort - println(ClassTag.Short.runtimeClass.isAssignableFrom(x.getClass)) + println(s"Checking if ${x.getClass} matches ${classTag[Short].runtimeClass}") println(ClassTag.Short.unapply(x)) + println(s"Checking if ${x.getClass} matches ${classTag[Char].runtimeClass}") + println(ClassTag.Char.unapply(x)) test(x) } { val x = 1.toChar - println(ClassTag.Char.runtimeClass.isAssignableFrom(x.getClass)) + println(s"Checking if ${x.getClass} matches ${classTag[Char].runtimeClass}") println(ClassTag.Char.unapply(x)) + println(s"Checking if ${x.getClass} matches ${classTag[Int].runtimeClass}") + println(ClassTag.Int.unapply(x)) test(x) } { val x = 1.toInt - println(ClassTag.Int.runtimeClass.isAssignableFrom(x.getClass)) + println(s"Checking if ${x.getClass} matches ${classTag[Int].runtimeClass}") println(ClassTag.Int.unapply(x)) + println(s"Checking if ${x.getClass} matches ${classTag[Long].runtimeClass}") + println(ClassTag.Long.unapply(x)) test(x) } { val x = 1.toLong - println(ClassTag.Long.runtimeClass.isAssignableFrom(x.getClass)) + println(s"Checking if ${x.getClass} matches ${classTag[Long].runtimeClass}") println(ClassTag.Long.unapply(x)) + println(s"Checking if ${x.getClass} matches ${classTag[Float].runtimeClass}") + println(ClassTag.Float.unapply(x)) test(x) } { val x = 1.toFloat - println(ClassTag.Float.runtimeClass.isAssignableFrom(x.getClass)) + println(s"Checking if ${x.getClass} matches ${classTag[Float].runtimeClass}") println(ClassTag.Float.unapply(x)) + println(s"Checking if ${x.getClass} matches ${classTag[Double].runtimeClass}") + println(ClassTag.Double.unapply(x)) test(x) } { val x = 1.toDouble - println(ClassTag.Double.runtimeClass.isAssignableFrom(x.getClass)) + println(s"Checking if ${x.getClass} matches ${classTag[Double].runtimeClass}") println(ClassTag.Double.unapply(x)) + println(s"Checking if ${x.getClass} matches ${classTag[Boolean].runtimeClass}") + println(ClassTag.Boolean.unapply(x)) test(x) } { val x = true - println(ClassTag.Boolean.runtimeClass.isAssignableFrom(x.getClass)) + println(s"Checking if ${x.getClass} matches ${classTag[Boolean].runtimeClass}") println(ClassTag.Boolean.unapply(x)) + println(s"Checking if ${x.getClass} matches ${classTag[Unit].runtimeClass}") + println(ClassTag.Unit.unapply(x)) test(x) } { val x = () - println(ClassTag.Unit.runtimeClass.isAssignableFrom(x.getClass)) + println(s"Checking if ${x.getClass} matches ${classTag[Unit].runtimeClass}") println(ClassTag.Unit.unapply(x)) + println(s"Checking if ${x.getClass} matches ${classTag[Byte].runtimeClass}") + println(ClassTag.Byte.unapply(x)) test(x) } -}
\ No newline at end of file +} diff --git a/test/files/run/virtpatmat_typetag.check b/test/files/run/virtpatmat_typetag.check index cac9d9a4d6..00df8b5e81 100644 --- a/test/files/run/virtpatmat_typetag.check +++ b/test/files/run/virtpatmat_typetag.check @@ -1,9 +1,9 @@ -1 is not a Int; it's a class java.lang.Integer +1 is a Int 1 is a java.lang.Integer 1 is not a java.lang.String; it's a class java.lang.Integer true is a Any woele is a java.lang.String -1 is not a Int; it's a class java.lang.Integer +1 is a Int 1 is a java.lang.Integer 1 is not a java.lang.String; it's a class java.lang.Integer true is a Any |