From 765386ff970af8d53aaa66a42b030e83043d471d Mon Sep 17 00:00:00 2001 From: James Iry Date: Mon, 14 Jan 2013 11:24:11 -0800 Subject: 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. --- .../scala/tools/nsc/transform/Erasure.scala | 23 ++++++++++++++++------ test/files/run/t5568.check | 9 +++++++++ test/files/run/t5568.scala | 18 +++++++++++++++++ 3 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 test/files/run/t5568.check create mode 100644 test/files/run/t5568.scala diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 7b9b13ae1c..58494cb18e 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/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 { diff --git a/test/files/run/t5568.check b/test/files/run/t5568.check new file mode 100644 index 0000000000..67aaf16e07 --- /dev/null +++ b/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 diff --git a/test/files/run/t5568.scala b/test/files/run/t5568.scala new file mode 100644 index 0000000000..7fc51fe86f --- /dev/null +++ b/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).##) + } +} -- cgit v1.2.3