Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SI-6318 fixes ClassTag.unapply for primitives #1265

Merged
merged 1 commit into from Sep 7, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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)
}
}