Browse files

SI-5568 Fixes verify error from getClass on refinement of value type

().asInstanceOf[AnyRef with Unit].getClass and
5.asInstanceOf[AnyRef with Int].getClass would cause a verify
error. Going the other way, i.e. [Unit with AnyRef] or [Int with AnyRef]
worked fine. This commit fixes it that both directions work out to
BoxedUnit or java.lang.Integer.
  • Loading branch information...
1 parent 621f7a5 commit 765386ff970af8d53aaa66a42b030e83043d471d @JamesIry JamesIry committed Jan 14, 2013
Showing with 44 additions and 6 deletions.
  1. +17 −6 src/compiler/scala/tools/nsc/transform/Erasure.scala
  2. +9 −0 test/files/run/t5568.check
  3. +18 −0 test/files/run/t5568.scala
View
23 src/compiler/scala/tools/nsc/transform/Erasure.scala
@@ -340,12 +340,18 @@ abstract class Erasure extends AddInterfaces
case _ => tp.deconst
}
}
- // Methods on Any/Object which we rewrite here while we still know what
- // is a primitive and what arrived boxed.
- private lazy val interceptedMethods = Set[Symbol](Any_##, Object_##, Any_getClass, AnyVal_getClass) ++ (
- // Each value class has its own getClass for ultra-precise class object typing.
+
+ // Each value class has its own getClass for ultra-precise class object typing.
+ private lazy val primitiveGetClassMethods = Set[Symbol](Any_getClass, AnyVal_getClass) ++ (
ScalaValueClasses map (_.tpe member nme.getClass_)
)
+
+ // ## requires a little translation
+ private lazy val poundPoundMethods = Set[Symbol](Any_##, Object_##)
+
+ // Methods on Any/Object which we rewrite here while we still know what
+ // is a primitive and what arrived boxed.
+ private lazy val interceptedMethods = poundPoundMethods ++ primitiveGetClassMethods
// -------- erasure on trees ------------------------------------------
@@ -1136,7 +1142,7 @@ abstract class Erasure extends AddInterfaces
args)
}
} else if (args.isEmpty && interceptedMethods(fn.symbol)) {
- if (fn.symbol == Any_## || fn.symbol == Object_##) {
+ if (poundPoundMethods.contains(fn.symbol)) {
// This is unattractive, but without it we crash here on ().## because after
// erasure the ScalaRunTime.hash overload goes from Unit => Int to BoxedUnit => Int.
// This must be because some earlier transformation is being skipped on ##, but so
@@ -1152,9 +1158,14 @@ abstract class Erasure extends AddInterfaces
} else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) {
// Rewrite 5.getClass to ScalaRunTime.anyValClass(5)
global.typer.typed(gen.mkRuntimeCall(nme.anyValClass, List(qual, typer.resolveClassTag(tree.pos, qual.tpe.widen))))
- } else if (fn.symbol == AnyVal_getClass) {
+ } else if (primitiveGetClassMethods.contains(fn.symbol)) {
+ // if we got here then we're trying to send a primitive getClass method to
+ // a) an Any, or
+ // b) a non-primitive, e.g. because the qualifier's type is a refinement type where part of the refinement is a primitive.
+ // if we use Object_getClass then things work out because we will call getClass on the boxed form of the Any or primitive
tree setSymbol Object_getClass
} else {
+ debugwarn(s"The symbol '${fn.symbol}' was interecepted but didn't match any cases, that means the intercepted methods set doesn't match the code")
tree
}
} else qual match {
View
9 test/files/run/t5568.check
@@ -0,0 +1,9 @@
+void
+int
+class scala.runtime.BoxedUnit
+class scala.runtime.BoxedUnit
+class java.lang.Integer
+class java.lang.Integer
+5
+5
+5
View
18 test/files/run/t5568.scala
@@ -0,0 +1,18 @@
+object Test {
+ final val UNIT: AnyRef with Unit = ().asInstanceOf[AnyRef with Unit]
+
+ def main(args: Array[String]): Unit = {
+ // these should give unboxed results
+ println(().getClass)
+ println(5.getClass)
+ // these should give boxed results
+ println(().asInstanceOf[AnyRef with Unit].getClass)
+ println(().asInstanceOf[Unit with AnyRef].getClass)
+ println(5.asInstanceOf[AnyRef with Int].getClass)
+ println(5.asInstanceOf[Int with AnyRef].getClass)
+ //make sure ## wasn't broken
+ println(5.##)
+ println((5.asInstanceOf[AnyRef]).##)
+ println((5:Any).##)
+ }
+}

0 comments on commit 765386f

Please sign in to comment.