From f7bc59bc2f6815cf6ca9cc17173f4335d2a0fd0b Mon Sep 17 00:00:00 2001 From: Sébastien Doeraene Date: Mon, 5 Jan 2015 13:11:13 +0100 Subject: Scala.js-friendly `ClassTag.unapply` Use `j.l.Class.isInstance` for Scala.js, so that `unapply` works correctly when referencing raw JavaScript classes. --- src/library/scala/reflect/ClassTag.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/library') diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index 2f4aa9cb84..e83f689ca7 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -94,9 +94,9 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial 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)) + val conforms = runtimeClass.isInstance(x) || (alternative != null && runtimeClass.isAssignableFrom(alternative)) if (conforms) Some(x.asInstanceOf[T]) else None } -- cgit v1.2.3 From 788f38871ca52bc22967dca22355f6a1affb4e06 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Fri, 13 Feb 2015 11:25:25 -0800 Subject: Simplify `ClassTag.unapply` Inline overloaded calls to `unapply`, so we can get rid of them in 2.13. Note that theres a lot of `box(unbox(x))` going on behind the scenes. Is this needed? --- src/library/scala/reflect/ClassTag.scala | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'src/library') diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index e83f689ca7..b9b4772870 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -71,20 +71,21 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial */ 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) + case x: Byte => unapplyImpl(x, classOf[Byte]) // erases to: if (x instanceof Byte) unapplyImpl(BoxesRunTime.boxToByte(BoxesRunTime.unboxToByte(x)), Byte.TYPE) + case x: Short => unapplyImpl(x, classOf[Short]) + case x: Char => unapplyImpl(x, classOf[Char]) + case x: Int => unapplyImpl(x, classOf[Int]) + case x: Long => unapplyImpl(x, classOf[Long]) + case x: Float => unapplyImpl(x, classOf[Float]) + case x: Double => unapplyImpl(x, classOf[Double]) + case x: Boolean => unapplyImpl(x, classOf[Boolean]) + case x: Unit => unapplyImpl(x, classOf[Unit]) + // TODO: move this next case up and remove the redundant check in unapplyImpl? + case _ if runtimeClass isInstance x => Some(x.asInstanceOf[T]) + case _ => 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 + // TODO: deprecate overloads in 2.12.0, remove in 2.13.0 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]) @@ -95,10 +96,9 @@ trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serial 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.isInstance(x) || (alternative != null && runtimeClass.isAssignableFrom(alternative)) - if (conforms) Some(x.asInstanceOf[T]) else None - } + private[this] def unapplyImpl(x: Any, primitiveCls: java.lang.Class[_]): Option[T] = + if (runtimeClass.isInstance(x) || runtimeClass.isAssignableFrom(primitiveCls)) Some(x.asInstanceOf[T]) + else None // case class accessories override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]] -- cgit v1.2.3 From bff86367607a713288a939639a654802349d1067 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Wed, 18 Feb 2015 12:46:21 -0800 Subject: Use if/then/else to avoid box(unbox(_)) --- src/library/scala/reflect/ClassTag.scala | 29 ++++++++++++++--------------- test/junit/scala/reflect/ClassTag.scala | 29 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 test/junit/scala/reflect/ClassTag.scala (limited to 'src/library') diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala index b9b4772870..9dd96183da 100644 --- a/src/library/scala/reflect/ClassTag.scala +++ b/src/library/scala/reflect/ClassTag.scala @@ -69,21 +69,20 @@ 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] = x match { - case null => None - case x: Byte => unapplyImpl(x, classOf[Byte]) // erases to: if (x instanceof Byte) unapplyImpl(BoxesRunTime.boxToByte(BoxesRunTime.unboxToByte(x)), Byte.TYPE) - case x: Short => unapplyImpl(x, classOf[Short]) - case x: Char => unapplyImpl(x, classOf[Char]) - case x: Int => unapplyImpl(x, classOf[Int]) - case x: Long => unapplyImpl(x, classOf[Long]) - case x: Float => unapplyImpl(x, classOf[Float]) - case x: Double => unapplyImpl(x, classOf[Double]) - case x: Boolean => unapplyImpl(x, classOf[Boolean]) - case x: Unit => unapplyImpl(x, classOf[Unit]) - // TODO: move this next case up and remove the redundant check in unapplyImpl? - case _ if runtimeClass isInstance x => Some(x.asInstanceOf[T]) - case _ => None - } + def unapply(x: Any): Option[T] = + if (null != x && ( + (runtimeClass.isInstance(x)) + || (x.isInstanceOf[Byte] && runtimeClass.isAssignableFrom(classOf[Byte])) + || (x.isInstanceOf[Short] && runtimeClass.isAssignableFrom(classOf[Short])) + || (x.isInstanceOf[Char] && runtimeClass.isAssignableFrom(classOf[Char])) + || (x.isInstanceOf[Int] && runtimeClass.isAssignableFrom(classOf[Int])) + || (x.isInstanceOf[Long] && runtimeClass.isAssignableFrom(classOf[Long])) + || (x.isInstanceOf[Float] && runtimeClass.isAssignableFrom(classOf[Float])) + || (x.isInstanceOf[Double] && runtimeClass.isAssignableFrom(classOf[Double])) + || (x.isInstanceOf[Boolean] && runtimeClass.isAssignableFrom(classOf[Boolean])) + || (x.isInstanceOf[Unit] && runtimeClass.isAssignableFrom(classOf[Unit]))) + ) Some(x.asInstanceOf[T]) + else None // TODO: deprecate overloads in 2.12.0, remove in 2.13.0 def unapply(x: Byte) : Option[T] = unapplyImpl(x, classOf[Byte]) diff --git a/test/junit/scala/reflect/ClassTag.scala b/test/junit/scala/reflect/ClassTag.scala new file mode 100644 index 0000000000..90cc981fc1 --- /dev/null +++ b/test/junit/scala/reflect/ClassTag.scala @@ -0,0 +1,29 @@ +package scala.reflect + +import org.junit.Test +import org.junit.Assert._ +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +import scala.tools.testing.AssertUtil._ + +class Misc + +@RunWith(classOf[JUnit4]) +class ClassTagTest { + def checkNotString[A: ClassTag](a: Any) = a match { case x: String => false case x: A => true case _ => false } + def checkNotInt[A: ClassTag](a: Any) = a match { case x: Int => false case x: A => true case _ => false } + def checkNotLong[A: ClassTag](a: Any) = a match { case x: Long => false case x: A => true case _ => false } + + @Test def checkMisc = assertTrue(checkNotString[Misc](new Misc)) + @Test def checkString = assertTrue(checkNotInt[String] ("woele")) + @Test def checkByte = assertTrue(checkNotInt[Byte] (0.toByte)) + @Test def checkShort = assertTrue(checkNotInt[Short] (0.toShort)) + @Test def checkChar = assertTrue(checkNotInt[Char] (0.toChar)) + @Test def checkInt = assertTrue(checkNotLong[Int] (0.toInt)) + @Test def checkLong = assertTrue(checkNotInt[Long] (0.toLong)) + @Test def checkFloat = assertTrue(checkNotInt[Float] (0.toFloat)) + @Test def checkDouble = assertTrue(checkNotInt[Double] (0.toDouble)) + @Test def checkBoolean = assertTrue(checkNotInt[Boolean](false)) + @Test def checkUnit = assertTrue(checkNotInt[Unit] ({})) +} \ No newline at end of file -- cgit v1.2.3