Skip to content

Commit e43eb18

Browse files
committed
Scala2Unpickler: Fix annotation argument handling
When an annotation argument is an Array, we can't know the element type of the Array until we've applied the argument to the annotation constructor, so we need to unpickle annotation arguments as untyped trees and rely on resolveConstructor to type them. This is the same logic we already use when unpickling Java classfiles since 610450f. Fixes #14223.
1 parent 0e4e5d5 commit e43eb18

File tree

5 files changed

+42
-10
lines changed

5 files changed

+42
-10
lines changed

compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -959,33 +959,33 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
959959
/** Read an annotation argument, which is pickled either
960960
* as a Constant or a Tree.
961961
*/
962-
protected def readAnnotArg(i: Int)(using Context): Tree = bytes(index(i)) match {
962+
protected def readAnnotArg(i: Int)(using Context): untpd.Tree = untpd.TypedSplice(bytes(index(i)) match
963963
case TREE => at(i, () => readTree())
964964
case _ => at(i, () =>
965965
readConstant() match
966966
case c: Constant => Literal(c)
967967
case tp: TermRef => ref(tp)
968968
)
969-
}
969+
)
970970

971971
/** Read a ClassfileAnnotArg (argument to a classfile annotation)
972972
*/
973-
private def readArrayAnnotArg()(using Context): Tree = {
973+
private def readArrayAnnotArg()(using Context): untpd.Tree = {
974974
readByte() // skip the `annotargarray` tag
975975
val end = readNat() + readIndex
976976
// array elements are trees representing instances of scala.annotation.Annotation
977-
SeqLiteral(
977+
untpd.JavaSeqLiteral(
978978
until(end, () => readClassfileAnnotArg(readNat())),
979-
TypeTree(defn.AnnotationClass.typeRef))
979+
untpd.TypeTree())
980980
}
981981

982-
private def readAnnotInfoArg()(using Context): Tree = {
982+
private def readAnnotInfoArg()(using Context): untpd.Tree = untpd.TypedSplice {
983983
readByte() // skip the `annotinfo` tag
984984
val end = readNat() + readIndex
985985
readAnnotationContents(end)
986986
}
987987

988-
protected def readClassfileAnnotArg(i: Int)(using Context): Tree = bytes(index(i)) match {
988+
protected def readClassfileAnnotArg(i: Int)(using Context): untpd.Tree = bytes(index(i)) match {
989989
case ANNOTINFO => at(i, () => readAnnotInfoArg())
990990
case ANNOTARGARRAY => at(i, () => readArrayAnnotArg())
991991
case _ => readAnnotArg(i)
@@ -997,22 +997,22 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas
997997
protected def readAnnotationContents(end: Int)(using Context): Tree = {
998998
val atp = readTypeRef()
999999
val args = {
1000-
val t = new ListBuffer[Tree]
1000+
val t = new ListBuffer[untpd.Tree]
10011001

10021002
while (readIndex != end) {
10031003
val argref = readNat()
10041004
t += {
10051005
if (isNameEntry(argref)) {
10061006
val name = at(argref, () => readName())
10071007
val arg = readClassfileAnnotArg(readNat())
1008-
NamedArg(name.asTermName, arg)
1008+
untpd.NamedArg(name.asTermName, arg)
10091009
}
10101010
else readAnnotArg(argref)
10111011
}
10121012
}
10131013
t.toList
10141014
}
1015-
resolveConstructor(atp, args)
1015+
untpd.resolveConstructor(atp, args)
10161016
}
10171017

10181018
/** Read an annotation and as a side effect store it into
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import kc.Encoder
2+
3+
def test: Unit =
4+
val cellEncoder = new Encoder[String] {
5+
override def encode: String = ""
6+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
val scala3Version = sys.props("plugin.scalaVersion")
2+
val scala2Version = sys.props("plugin.scala2Version")
3+
4+
lazy val lib = project.in(file("lib"))
5+
.settings(
6+
scalaVersion := scala2Version
7+
)
8+
9+
lazy val app = project.in(file("app"))
10+
.dependsOn(lib)
11+
.settings(
12+
scalaVersion := scala3Version
13+
)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package kc
2+
3+
trait Encoder[E] {
4+
def encode: E
5+
6+
@SuppressWarnings(Array("foo"))
7+
def tag1: Encoder[E] = ???
8+
9+
// Make sure we handle empty Array literals too where we can't guess the Array type from its elements
10+
@SuppressWarnings(Array())
11+
def tag2: Encoder[E] = ???
12+
}

sbt-test/scala2-compat/i14223/test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
> app/compile

0 commit comments

Comments
 (0)