summaryrefslogtreecommitdiff
path: root/src/library/scala/reflect/ClassTag.scala
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-09-06 21:05:17 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-09-06 23:19:20 +0200
commit6a740332c7bfd56b20993be6ecd0bf818104f56c (patch)
tree6884bd48506c9e2468d07cfcf7433121c04cfac2 /src/library/scala/reflect/ClassTag.scala
parentadf2d3632b07eef4fc2303aef994e66584a73f49 (diff)
downloadscala-6a740332c7bfd56b20993be6ecd0bf818104f56c.tar.gz
scala-6a740332c7bfd56b20993be6ecd0bf818104f56c.tar.bz2
scala-6a740332c7bfd56b20993be6ecd0bf818104f56c.zip
SI-6318 fixes ClassTag.unapply for primitives
ClassTag.unapply now has overloads for primitive value classes so that it can preserve boxiness when performing subtyping tests. First I wanted to annotate ClassTag.unapply with a ClassTag itself, i.e. to transform its signature from "def unapply(x: Any): Option[T]" to "def unapply[U: ClassTag](x: U): Option[T]". But then virtpatmat_typetag.scala exhibited a nasty problem. When pattern matching with this unapply, patmat first infers U as something and then tries to pattern match against this inferred type. And if U gets inferred as an abstract type itself, bad things happen: warning: The outer reference in this type test cannot be checked at run time. That's why I decided to drop the ClassTag idea and go with 9 extra overloads. Not very beautiful, but definitely robust.
Diffstat (limited to 'src/library/scala/reflect/ClassTag.scala')
-rw-r--r--src/library/scala/reflect/ClassTag.scala21
1 files changed, 20 insertions, 1 deletions
diff --git a/src/library/scala/reflect/ClassTag.scala b/src/library/scala/reflect/ClassTag.scala
index 5255c44f10..8ce06d611e 100644
--- a/src/library/scala/reflect/ClassTag.scala
+++ b/src/library/scala/reflect/ClassTag.scala
@@ -54,7 +54,26 @@ 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] = if (x != null && runtimeClass.isAssignableFrom(x.getClass)) Some(x.asInstanceOf[T]) else None
+ 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)
+
+ 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
+ }
/** case class accessories */
override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]]