From 38ca9dec8807ddce36a988bf13b367f4d6f03b9e Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Wed, 18 May 2016 15:24:45 +0200 Subject: SI-9671, SI-7397 fix null.asInstanceOf[Int] when pt erases to Object Erasure first replaces null.asInstanceOf[Int] by unbox(null). If the expected type erases to object, erasure then introduces a box operation, yielding box(unbox(null)). Note that this value is a box of zero, not null. Erasure has an optimization to replace box(unbox(x)) in case x is of primitive type. 60f1b4b extended this to the case when x is null, which is incorrect in general. The reason was to prevent creating a primitive box to be stored in the unused generic field when creating an instance of a specialized class. A special case ensures that this optimization is still performed. --- test/junit/scala/issues/BytecodeTest.scala | 10 +++ test/junit/scala/issues/RunTest.scala | 98 +++++++++++++++++++++++++++++- 2 files changed, 107 insertions(+), 1 deletion(-) (limited to 'test/junit/scala/issues') diff --git a/test/junit/scala/issues/BytecodeTest.scala b/test/junit/scala/issues/BytecodeTest.scala index a720f20718..7b9474b52e 100644 --- a/test/junit/scala/issues/BytecodeTest.scala +++ b/test/junit/scala/issues/BytecodeTest.scala @@ -419,6 +419,16 @@ class BytecodeTest extends ClearAfterClass { assertInvoke(getSingleMethod(c, "f3"), "java/lang/Object", "hashCode") assertInvoke(getSingleMethod(c, "f4"), "java/lang/Object", "toString") } + + @Test + def superConstructorArgumentInSpecializedClass(): Unit = { + // see comment in SpecializeTypes.forwardCtorCall + val code = "case class C[@specialized(Int) T](_1: T)" + val List(c, cMod, cSpec) = compileClasses(compiler)(code) + assertSameSummary(getSingleMethod(cSpec, ""), + // pass `null` to super constructor, no box-unbox, no Integer created + List(ALOAD, ILOAD, PUTFIELD, ALOAD, ACONST_NULL, "", RETURN)) + } } object invocationReceiversTestCode { diff --git a/test/junit/scala/issues/RunTest.scala b/test/junit/scala/issues/RunTest.scala index 148009c912..b81a3e1d6f 100644 --- a/test/junit/scala/issues/RunTest.scala +++ b/test/junit/scala/issues/RunTest.scala @@ -10,8 +10,8 @@ import scala.tools.reflect.ToolBox import scala.tools.testing.ClearAfterClass object RunTest { - class VC(val x: Any) extends AnyVal + class VCI(val x: Int) extends AnyVal { override def toString = "" + x } } @RunWith(classOf[JUnit4]) @@ -154,4 +154,100 @@ class RunTest extends ClearAfterClass { val u = Void.TYPE assertEquals(run[(Class[_], Class[_])](code), (u, u)) } + + @Test + def t9671(): Unit = { + val code = + """import scala.issues.RunTest.VCI + | + |def f1(a: Any) = "" + a + |def f2(a: AnyVal) = "" + a + |def f3[T](a: T) = "" + a + |def f4(a: Int) = "" + a + |def f5(a: VCI) = "" + a + |def f6(u: Unit) = "" + u + | + |def n1: AnyRef = null + |def n2: Null = null + |def n3: Any = null + |def n4[T]: T = null.asInstanceOf[T] + | + |def npe(s: => String) = try { s; throw new Error() } catch { case _: NullPointerException => "npe" } + | + | f1(null.asInstanceOf[Int]) + + | f1( n1.asInstanceOf[Int]) + + | f1( n2.asInstanceOf[Int]) + + | f1( n3.asInstanceOf[Int]) + + | f1( n4[Int]) + // "null" + |"-" + + | f1(null.asInstanceOf[VCI]) + + |npe(f1( n1.asInstanceOf[VCI])) + // SI-8097 + | f1( n2.asInstanceOf[VCI]) + + |npe(f1( n3.asInstanceOf[VCI])) + // SI-8097 + | f1( n4[VCI]) + // "null" + |"-" + + | f1(null.asInstanceOf[Unit]) + // "null", SI-9066 + | f1( n1.asInstanceOf[Unit]) + // "null", SI-9066 + | f1( n2.asInstanceOf[Unit]) + // "null", SI-9066 + | f1( n3.asInstanceOf[Unit]) + // "null", SI-9066 + | f1( n4[Unit]) + // "null" + |"-" + + | f2(null.asInstanceOf[Int]) + + | f2( n1.asInstanceOf[Int]) + + | f2( n2.asInstanceOf[Int]) + + | f2( n3.asInstanceOf[Int]) + + | f2( n4[Int]) + // "null" + |"-" + + | f2(null.asInstanceOf[VCI]) + + |npe(f2( n1.asInstanceOf[VCI])) + // SI-8097 + | f2( n2.asInstanceOf[VCI]) + + |npe(f2( n3.asInstanceOf[VCI])) + // SI-8097 + | f2( n4[VCI]) + // "null" + |"-" + + | f2(null.asInstanceOf[Unit]) + // "null", SI-9066 + | f2( n1.asInstanceOf[Unit]) + // "null", SI-9066 + | f2( n2.asInstanceOf[Unit]) + // "null", SI-9066 + | f2( n3.asInstanceOf[Unit]) + // "null", SI-9066 + | f2( n4[Unit]) + // "null" + |"-" + + | f3(null.asInstanceOf[Int]) + + | f3( n1.asInstanceOf[Int]) + + | f3( n2.asInstanceOf[Int]) + + | f3( n3.asInstanceOf[Int]) + + | f3( n4[Int]) + // "null" + |"-" + + | f3(null.asInstanceOf[VCI]) + + |npe(f3( n1.asInstanceOf[VCI])) + // SI-8097 + | f3( n2.asInstanceOf[VCI]) + + |npe(f3( n3.asInstanceOf[VCI])) + // SI-8097 + | f3( n4[VCI]) + // "null" + |"-" + + | f3(null.asInstanceOf[Unit]) + // "null", SI-9066 + | f3( n1.asInstanceOf[Unit]) + // "null", SI-9066 + | f3( n2.asInstanceOf[Unit]) + // "null", SI-9066 + | f3( n3.asInstanceOf[Unit]) + // "null", SI-9066 + | f3( n4[Unit]) + // "null" + |"-" + + | f4(null.asInstanceOf[Int]) + + | f4( n1.asInstanceOf[Int]) + + | f4( n2.asInstanceOf[Int]) + + | f4( n3.asInstanceOf[Int]) + + | f4( n4[Int]) + + |"-" + + | f5(null.asInstanceOf[VCI]) + + |npe(f5( n1.asInstanceOf[VCI])) + // SI-8097 + | f5( n2.asInstanceOf[VCI]) + + |npe(f5( n3.asInstanceOf[VCI])) + // SI-8097 + |npe(f5( n4[VCI])) + // SI-8097 + |"-" + + | f6(null.asInstanceOf[Unit]) + // "null", SI-9066 + | f6( n1.asInstanceOf[Unit]) + // "null", SI-9066 + | f6( n2.asInstanceOf[Unit]) + // "null", SI-9066 + | f6( n3.asInstanceOf[Unit]) + // "null", SI-9066 + | f6( n4[Unit]) // "null" + """.stripMargin + + assertEquals(run[String](code), + "0000null-0npe0npenull-nullnullnullnullnull-0000null-0npe0npenull-nullnullnullnullnull-0000null-0npe0npenull-nullnullnullnullnull-00000-0npe0npenpe-nullnullnullnullnull") + } } -- cgit v1.2.3