Skip to content

Commit

Permalink
Merge pull request #1265 from scalamacros/ticket/6318
Browse files Browse the repository at this point in the history
SI-6318 fixes ClassTag.unapply for primitives
  • Loading branch information
jsuereth committed Sep 7, 2012
2 parents bc8a7c8 + 6a74033 commit b7e0872
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 1 deletion.
21 changes: 20 additions & 1 deletion src/library/scala/reflect/ClassTag.scala
Expand Up @@ -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[_]]
Expand Down
3 changes: 3 additions & 0 deletions test/files/run/t6318_derived.check
@@ -0,0 +1,3 @@
Some(X)
true
Some(X)
15 changes: 15 additions & 0 deletions test/files/run/t6318_derived.scala
@@ -0,0 +1,15 @@
import scala.reflect.{ClassTag, classTag}

object Test extends App {
def test[T: ClassTag](x: T) {
println(classTag[T].runtimeClass.isAssignableFrom(x.getClass))
println(classTag[T].unapply(x))
}

class X(val x: Int) extends AnyVal { override def toString = "X" }
val x = new X(1)
// the commented line crashes because of SI-6326
//println(classTag[X].runtimeClass.isAssignableFrom(x.getClass))
println(classTag[X].unapply(x))
test(x)
}
36 changes: 36 additions & 0 deletions test/files/run/t6318_primitives.check
@@ -0,0 +1,36 @@
true
Some(1)
false
None
true
Some(1)
false
None
true
Some()
false
None
true
Some(1)
false
None
true
Some(1)
false
None
true
Some(1.0)
false
None
true
Some(1.0)
false
None
true
Some(true)
false
None
true
Some(())
false
None
71 changes: 71 additions & 0 deletions test/files/run/t6318_primitives.scala
@@ -0,0 +1,71 @@
import scala.reflect.{ClassTag, classTag}

object Test extends App {
def test[T: ClassTag](x: T) {
println(classTag[T].runtimeClass.isAssignableFrom(x.getClass))
println(classTag[T].unapply(x))
}

{
val x = 1.toByte
println(ClassTag.Byte.runtimeClass.isAssignableFrom(x.getClass))
println(ClassTag.Byte.unapply(x))
test(x)
}

{
val x = 1.toShort
println(ClassTag.Short.runtimeClass.isAssignableFrom(x.getClass))
println(ClassTag.Short.unapply(x))
test(x)
}

{
val x = 1.toChar
println(ClassTag.Char.runtimeClass.isAssignableFrom(x.getClass))
println(ClassTag.Char.unapply(x))
test(x)
}

{
val x = 1.toInt
println(ClassTag.Int.runtimeClass.isAssignableFrom(x.getClass))
println(ClassTag.Int.unapply(x))
test(x)
}

{
val x = 1.toLong
println(ClassTag.Long.runtimeClass.isAssignableFrom(x.getClass))
println(ClassTag.Long.unapply(x))
test(x)
}

{
val x = 1.toFloat
println(ClassTag.Float.runtimeClass.isAssignableFrom(x.getClass))
println(ClassTag.Float.unapply(x))
test(x)
}

{
val x = 1.toDouble
println(ClassTag.Double.runtimeClass.isAssignableFrom(x.getClass))
println(ClassTag.Double.unapply(x))
test(x)
}

{
val x = true
println(ClassTag.Boolean.runtimeClass.isAssignableFrom(x.getClass))
println(ClassTag.Boolean.unapply(x))
test(x)
}

{
val x = ()
println(ClassTag.Unit.runtimeClass.isAssignableFrom(x.getClass))
println(ClassTag.Unit.unapply(x))
test(x)
}
}

0 comments on commit b7e0872

Please sign in to comment.