diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2016-11-18 16:49:25 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2016-12-02 11:09:31 +1000 |
commit | 880aec04e82ad3a9a2feb3b83b779f192d84e01e (patch) | |
tree | f668cf6c27ce152fd7624e081fac2623812b2d24 | |
parent | 73678d4dafe250f0b38df2e953787af26b1a4ee3 (diff) | |
download | scala-880aec04e82ad3a9a2feb3b83b779f192d84e01e.tar.gz scala-880aec04e82ad3a9a2feb3b83b779f192d84e01e.tar.bz2 scala-880aec04e82ad3a9a2feb3b83b779f192d84e01e.zip |
SI-10069 Fix code gen errors with array updates, Nothing
Crashes in ASM or VerifyErrors used to occur when assigning
an expression of type Nothing to an element of a primitive array.
This commit adapts the RHS of the assignment to the element
type to correct this. `adapt` contains logic to insert an
`ATHROW` of the slot of type `Nothing$`, which makes everything
line up. The subsequent array stores become dead code and are
dropped later on in code gen, so the test case compiles to:
public void foo0(double[]);
Code:
0: bipush 42
2: istore_2
3: aload_1
4: iconst_0
5: aload_0
6: invokevirtual #30 // Method throwExpected:()Lscala/runtime/Nothing$;
9: athrow
I found a similar bug in the emission of primitive unboxing and
fixed that too.
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala | 4 | ||||
-rw-r--r-- | test/files/run/t10069.scala | 34 | ||||
-rw-r--r-- | test/files/run/t10069b.scala | 13 |
3 files changed, 49 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index b0815b0008..c7952ffe94 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -168,7 +168,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { } else if (scalaPrimitives.isArraySet(code)) { val List(a1, a2) = args genLoad(a1, INT) - genLoad(a2) + genLoad(a2, elementType) generatedType = UNIT bc.astore(elementType) } else { @@ -630,7 +630,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { generatedType = methodBTypeFromSymbol(fun.symbol).returnType case Apply(fun, List(expr)) if currentRun.runDefinitions.isBox(fun.symbol) => - val nativeKind = tpeTK(expr) + val nativeKind = typeToBType(fun.symbol.firstParam.info) genLoad(expr, nativeKind) val MethodNameAndType(mname, methodType) = srBoxesRuntimeBoxToMethods(nativeKind) bc.invokestatic(srBoxesRunTimeRef.internalName, mname, methodType.descriptor, itf = false, app.pos) diff --git a/test/files/run/t10069.scala b/test/files/run/t10069.scala new file mode 100644 index 0000000000..4e70b7e814 --- /dev/null +++ b/test/files/run/t10069.scala @@ -0,0 +1,34 @@ +object Expected extends Exception +object Test { + def throwExpected: Nothing = throw Expected + def foo0(a: Array[Double]) = { // does compile for Int instead of Double + val v = 42 + a(0) = throwExpected // was crash in code gen: java.lang.NegativeArraySizeException + } + + def foo1(a: Array[Double]) = { // does compile for Int instead of Double + a(0) = throwExpected // was VerifyError at runtime + } + + def foo2(a: Array[Int]) = { // does compile for Int instead of Double + a(0) = throwExpected // was VerifyError at runtime + } + + def foo3(a: Array[String]) = { // does compile for Int instead of Double + a(0) = throwExpected // was already working + } + + + def main(args: Array[String]): Unit = { + check(foo0(new Array[Double](1))) + check(foo1(new Array[Double](1))) + check(foo2(new Array[Int](1))) + check(foo3(new Array[String](1))) + } + def check(f: => Any) { + try {f ; sys.error("no exception thrown") + } catch { + case Expected => + } + } +} diff --git a/test/files/run/t10069b.scala b/test/files/run/t10069b.scala new file mode 100644 index 0000000000..c9d652bb0c --- /dev/null +++ b/test/files/run/t10069b.scala @@ -0,0 +1,13 @@ +object Test { + def main(args: Array[String]): Unit = { + try { + Int.box(???) // crashed the compiler: java.util.NoSuchElementException: key not found: Lscala/runtime/Nothing$; + sys.error("no exception") + } catch { + case _: NotImplementedError => + // oka + case e: Throwable => + sys.error("wrong exception: " + e) + } + } +} |