Skip to content

Commit 57a5da8

Browse files
committed
Require seeing ScalaSig before scanning for Scala pickling annotations
An alternative fix for #15166, which aligns with the behavior of the Scala 2 classfile parser. Before this commit, all classfiles, including those produced by the Java compiler and compilers of other JVM languages, were scanned for Scala pickling annotations. In certain situations (as in tests/pos/i15166), this is problematic, as the denotation of an annotation symbol defined as a Java inner class may be forced before the inner class table is populated and setClassInfo is called on the class root. We avoid this situation by only performing the pickling annotation scan for those classfiles having the `ScalaSig` attribute, i.e. those produced by the Scala 2 compiler. We also drop support for pickling TASTy using the classfile annotations `scala.annotation.internal.TASTYSignature` and `scala.annotation.internal.TASTYLongSignature`. These were never used by the compiler, there are no plans for future use, and preserving support would complicate this fix.
1 parent 5cc0490 commit 57a5da8

File tree

7 files changed

+26
-10
lines changed

7 files changed

+26
-10
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -920,8 +920,6 @@ class Definitions {
920920
@tu lazy val ScalaStrictFPAnnot: ClassSymbol = requiredClass("scala.annotation.strictfp")
921921
@tu lazy val ScalaStaticAnnot: ClassSymbol = requiredClass("scala.annotation.static")
922922
@tu lazy val SerialVersionUIDAnnot: ClassSymbol = requiredClass("scala.SerialVersionUID")
923-
@tu lazy val TASTYSignatureAnnot: ClassSymbol = requiredClass("scala.annotation.internal.TASTYSignature")
924-
@tu lazy val TASTYLongSignatureAnnot: ClassSymbol = requiredClass("scala.annotation.internal.TASTYLongSignature")
925923
@tu lazy val TailrecAnnot: ClassSymbol = requiredClass("scala.annotation.tailrec")
926924
@tu lazy val ThreadUnsafeAnnot: ClassSymbol = requiredClass("scala.annotation.threadUnsafe")
927925
@tu lazy val ConstructorOnlyAnnot: ClassSymbol = requiredClass("scala.annotation.constructorOnly")

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ class ClassfileParser(
871871

872872
/** Parse inner classes. Expects `in.bp` to point to the superclass entry.
873873
* Restores the old `bp`.
874-
* @return true iff classfile is from Scala, so no Java info needs to be read.
874+
* @return Some(unpickler) iff classfile is from Scala, so no Java info needs to be read.
875875
*/
876876
def unpickleOrParseInnerClasses()(using ctx: Context, in: DataReader): Option[Embedded] = {
877877
val oldbp = in.bp
@@ -1028,7 +1028,7 @@ class ClassfileParser(
10281028
// attribute isn't, this classfile is a compilation artifact.
10291029
return Some(NoEmbedded)
10301030

1031-
if (scan(tpnme.RuntimeVisibleAnnotationATTR) || scan(tpnme.RuntimeInvisibleAnnotationATTR)) {
1031+
if (scan(tpnme.ScalaSignatureATTR) && scan(tpnme.RuntimeVisibleAnnotationATTR)) {
10321032
val attrLen = in.nextInt
10331033
val nAnnots = in.nextChar
10341034
var i = 0
@@ -1039,14 +1039,10 @@ class ClassfileParser(
10391039
while (j < nArgs) {
10401040
val argName = pool.getName(in.nextChar)
10411041
if (argName.name == nme.bytes) {
1042-
if (attrClass == defn.ScalaSignatureAnnot)
1042+
if attrClass == defn.ScalaSignatureAnnot then
10431043
return unpickleScala(parseScalaSigBytes)
1044-
else if (attrClass == defn.ScalaLongSignatureAnnot)
1044+
else if attrClass == defn.ScalaLongSignatureAnnot then
10451045
return unpickleScala(parseScalaLongSigBytes)
1046-
else if (attrClass == defn.TASTYSignatureAnnot)
1047-
return unpickleTASTY(parseScalaSigBytes)
1048-
else if (attrClass == defn.TASTYLongSignatureAnnot)
1049-
return unpickleTASTY(parseScalaLongSigBytes)
10501046
}
10511047
parseAnnotArg(skip = true)
10521048
j += 1

library/src/scala/annotation/internal/TASTYLongSignature.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
@Retention(RetentionPolicy.RUNTIME)
99
@Target(ElementType.TYPE)
10+
@Deprecated
1011
public @interface TASTYLongSignature {
1112
public String[] bytes();
1213
}

library/src/scala/annotation/internal/TASTYSignature.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
@Retention(RetentionPolicy.RUNTIME)
99
@Target(ElementType.TYPE)
10+
@Deprecated
1011
public @interface TASTYSignature {
1112
public String bytes();
1213
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import java.lang.annotation.Retention;
2+
import java.lang.annotation.RetentionPolicy;
3+
4+
@InterfaceStability_JAVA_ONLY_1.Evolving(bytes="no")
5+
public class InterfaceAudience_JAVA_ONLY_1 {
6+
@Retention(RetentionPolicy.RUNTIME)
7+
public @interface Public { String bytes(); }
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import java.lang.annotation.Retention;
2+
import java.lang.annotation.RetentionPolicy;
3+
4+
@InterfaceAudience_JAVA_ONLY_1.Public(bytes="yes")
5+
public class InterfaceStability_JAVA_ONLY_1 {
6+
@Retention(RetentionPolicy.RUNTIME)
7+
public @interface Evolving { String bytes(); }
8+
}

tests/pos/i15166/Test_2.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// scalac: -Xfatal-warnings
2+
object Test {
3+
val x: InterfaceAudience_JAVA_ONLY_1.Public = ???
4+
}

0 commit comments

Comments
 (0)