diff options
author | clhodapp <clhodapp1@gmail.com> | 2014-05-29 21:44:46 -0700 |
---|---|---|
committer | clhodapp <clhodapp1@gmail.com> | 2014-06-10 21:19:33 -0700 |
commit | 1a20152e97fe772e299fa3eb2608bedcea95cb82 (patch) | |
tree | e656a2998b292b9189f8a6e6072beaf63e24fed1 /src/library/scala/reflect/ClassTag.scala | |
parent | da2896c4e5a1e037bc3a473bc9d1689378816a32 (diff) | |
download | scala-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/library/scala/reflect/ClassTag.scala')
-rw-r--r-- | src/library/scala/reflect/ClassTag.scala | 48 |
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[_]] |