summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorclhodapp <clhodapp1@gmail.com>2014-05-29 21:44:46 -0700
committerclhodapp <clhodapp1@gmail.com>2014-06-10 21:19:33 -0700
commit1a20152e97fe772e299fa3eb2608bedcea95cb82 (patch)
treee656a2998b292b9189f8a6e6072beaf63e24fed1 /src
parentda2896c4e5a1e037bc3a473bc9d1689378816a32 (diff)
downloadscala-1a20152e97fe772e299fa3eb2608bedcea95cb82.tar.gz
scala-1a20152e97fe772e299fa3eb2608bedcea95cb82.tar.bz2
scala-1a20152e97fe772e299fa3eb2608bedcea95cb82.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/library/scala/reflect/ClassTag.scala48
1 files changed, 29 insertions, 19 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[_]]