From 1a20152e97fe772e299fa3eb2608bedcea95cb82 Mon Sep 17 00:00:00 2001 From: clhodapp Date: Thu, 29 May 2014 21:44:46 -0700 Subject: SI-6967 Fix ClassTag unapply for primitives This commit fixes the behavior of ClassTag's Any-accepting unapply overload. Previously, ClassTag had overloads of unapply that accepted all of the Java primitive aliases (language-supported magic classes extending AnyVal), as well as an implementation that accepted an Any. All of the AnyVal-accepting (more specific) versions of the methods worked correctly. However, the Any-accepting version incorrectly handled these types. For example, ClassTag.Int.unapply(3) would return Some(3) (through the Int-accepting overload), while ClassTag.Int.unapply(3: Any) would return None (through the Any-accepting overload). This commit unifies these behaviors, making ClassTag.Int.unapply(3: Any) return Some(3). It accomplishes this by adding a pattern match on the type of that method's argument, which will delegate to one of the more-specifically-typed overloads if possible. It also improves the formatting of the code a bit. One thing to note (though I doubt anyone will ever do this based on this message) is that the AnyVal-subtype-accepting overloads should be removed in Scala 2.12, as they are unneeded. I placed a note to this effect into the code. --- test/files/run/t6318_primitives.check | 54 ++++++++++++++++++++++----------- test/files/run/t6318_primitives.scala | 40 +++++++++++++++++------- test/files/run/virtpatmat_typetag.check | 4 +-- 3 files changed, 67 insertions(+), 31 deletions(-) (limited to 'test') 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 -- cgit v1.2.3