scala/scala#10976 changed the pickle format in 2.13.17. A macro-related bug resulting from this change was identified in scala/scala-dev#893 (scala/scala-dev#893 (comment)) and deemed acceptable (scala/scala-dev#893 (comment)), but the problem is not limited to macros. It also affects forward compatibility of runtime reflection. This problem does not show up in partest or in the community build where all artifacts are produced by the same compiler version.
Reproduction:
TriggerClass.scala is lifted directly from test/files/run/sd884b/A.scala:
package picklerepro
object T { def i = 0 }
class ann(val x: Int = 1, val y: Int = T.i) extends scala.annotation.StaticAnnotation
class kon(val x: Int = 1, val y: Int = 2) extends scala.annotation.ConstantAnnotation
class TriggerClass {
@ann(x = 11) def m1: Int = 1
@ann(y = 22) def m2: Int = 1
@kon(x = 11) def k1: Int = 1
@kon(y = 22) def k2: Int = 1
}
ReflectionRunner.scala is the actual test:
package picklerepro
import scala.reflect.runtime.universe._
object ReflectionRunner {
def main(args: Array[String]): Unit = {
val className = "picklerepro.TriggerClass"
println(s"scala.util.Properties.versionNumberString = ${scala.util.Properties.versionNumberString}")
println(s"Loading class: $className")
val mirror = runtimeMirror(getClass.getClassLoader)
val javaCls = Class.forName(className)
val sym = mirror.classSymbol(javaCls)
println(s"Got symbol (lazy): $sym")
println("Forcing .info (this triggers the UnPickler) ...")
val info = sym.info
println(s"Info loaded: $info")
println("Walking members and forcing their annotations ...")
val members = info.members.toList
.filter(s => s.name.toString.startsWith("m") || s.name.toString.startsWith("k"))
.sortBy(_.name.toString)
for (m <- members) {
val a = m.annotations.headOption.getOrElse(throw new RuntimeException(s"no annotation on $m"))
println(s" $m -> $a")
}
println("OK")
}
}
To trigger the bug, compile TriggerClass.scala with 2.13.18 and then run ReflectionRunner on 2.13.16:
#!/usr/bin/env bash
SCALA_2_13_16=${SCALA_2_13_16:-$HOME/scala-2.13.16}
SCALA_2_13_18=${SCALA_2_13_18:-$HOME/scala-2.13.18}
here=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT
trigger_classes="$work/trigger"
trigger_jar="$work/trigger.jar"
runner_classes="$work/runner"
mkdir -p "$trigger_classes" "$runner_classes"
"$SCALA_2_13_18/bin/scalac" -d "$trigger_classes" "$here/TriggerClass.scala"
( cd "$trigger_classes" && jar cf "$trigger_jar" . )
"$SCALA_2_13_16/bin/scalac" -d "$runner_classes" "$here/ReflectionRunner.scala"
cp="$SCALA_2_13_16/lib/scala-library.jar:$SCALA_2_13_16/lib/scala-reflect.jar:$runner_classes:$trigger_jar"
java -cp "$cp" picklerepro.ReflectionRunner
It fails with
Exception in thread "main" java.lang.RuntimeException: error reading Scala signature of picklerepro.TriggerClass: unsafe symbol defaultArg (child of package meta) in runtime reflection universe
at scala.reflect.internal.pickling.UnPickler.unpickle(UnPickler.scala:48)
scala/scala#10976 changed the pickle format in 2.13.17. A macro-related bug resulting from this change was identified in scala/scala-dev#893 (scala/scala-dev#893 (comment)) and deemed acceptable (scala/scala-dev#893 (comment)), but the problem is not limited to macros. It also affects forward compatibility of runtime reflection. This problem does not show up in partest or in the community build where all artifacts are produced by the same compiler version.
Reproduction:
TriggerClass.scalais lifted directly fromtest/files/run/sd884b/A.scala:ReflectionRunner.scalais the actual test:To trigger the bug, compile
TriggerClass.scalawith 2.13.18 and then runReflectionRunneron 2.13.16:It fails with