Skip to content

Commit

Permalink
Use names instead of type symbols when scanning for pickling annotations
Browse files Browse the repository at this point in the history
When scanning for Scala pickling annotations, all annotations in all
classfiles (including those produced by the Java compiler) are considered.

Before this commit, a Type and Symbol were created for each discovered
annotation and comparared to the known Scala signature annotation types.
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.

Comparing names (as strings) rather than type symbols avoids this situation.

Fixes scala#15166
  • Loading branch information
griggt committed May 19, 2022
1 parent 64815bb commit e4b1cfe
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 9 deletions.
4 changes: 0 additions & 4 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -961,13 +961,9 @@ class Definitions {
@tu lazy val NativeAnnot: ClassSymbol = requiredClass("scala.native")
@tu lazy val RepeatedAnnot: ClassSymbol = requiredClass("scala.annotation.internal.Repeated")
@tu lazy val SourceFileAnnot: ClassSymbol = requiredClass("scala.annotation.internal.SourceFile")
@tu lazy val ScalaSignatureAnnot: ClassSymbol = requiredClass("scala.reflect.ScalaSignature")
@tu lazy val ScalaLongSignatureAnnot: ClassSymbol = requiredClass("scala.reflect.ScalaLongSignature")
@tu lazy val ScalaStrictFPAnnot: ClassSymbol = requiredClass("scala.annotation.strictfp")
@tu lazy val ScalaStaticAnnot: ClassSymbol = requiredClass("scala.annotation.static")
@tu lazy val SerialVersionUIDAnnot: ClassSymbol = requiredClass("scala.SerialVersionUID")
@tu lazy val TASTYSignatureAnnot: ClassSymbol = requiredClass("scala.annotation.internal.TASTYSignature")
@tu lazy val TASTYLongSignatureAnnot: ClassSymbol = requiredClass("scala.annotation.internal.TASTYLongSignature")
@tu lazy val TailrecAnnot: ClassSymbol = requiredClass("scala.annotation.tailrec")
@tu lazy val ThreadUnsafeAnnot: ClassSymbol = requiredClass("scala.annotation.threadUnsafe")
@tu lazy val ConstructorOnlyAnnot: ClassSymbol = requiredClass("scala.annotation.constructorOnly")
Expand Down
16 changes: 11 additions & 5 deletions compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ object ClassfileParser {
mapOver(tp)
}
}

private inline def sigOfClassName(n: String) = s"L$n;"
val ScalaSignatureAnnot: String = sigOfClassName("scala.reflect.ScalaSignature")
val ScalaLongSignatureAnnot: String = sigOfClassName("scala.reflect.ScalaLongSignature")
val TASTYSignatureAnnot: String = sigOfClassName("scala.annotation.internal.TASTYSignature")
val TASTYLongSignatureAnnot: String = sigOfClassName("scala.annotation.internal.TASTYLongSignature")
}

class ClassfileParser(
Expand Down Expand Up @@ -1004,19 +1010,19 @@ class ClassfileParser(
val nAnnots = in.nextChar
var i = 0
while (i < nAnnots) {
val attrClass = pool.getType(in.nextChar).typeSymbol
val attrSig = pool.getExternalName(in.nextChar).value
val nArgs = in.nextChar
var j = 0
while (j < nArgs) {
val argName = pool.getName(in.nextChar)
if (argName.name == nme.bytes) {
if (attrClass == defn.ScalaSignatureAnnot)
if attrSig == ScalaSignatureAnnot then
return unpickleScala(parseScalaSigBytes)
else if (attrClass == defn.ScalaLongSignatureAnnot)
else if attrSig == ScalaLongSignatureAnnot then
return unpickleScala(parseScalaLongSigBytes)
else if (attrClass == defn.TASTYSignatureAnnot)
else if attrSig == TASTYSignatureAnnot then
return unpickleTASTY(parseScalaSigBytes)
else if (attrClass == defn.TASTYLongSignatureAnnot)
else if attrSig == TASTYLongSignatureAnnot then
return unpickleTASTY(parseScalaLongSigBytes)
}
parseAnnotArg(skip = true)
Expand Down
8 changes: 8 additions & 0 deletions tests/pos/i15166/InterfaceAudience_JAVA_ONLY_1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@InterfaceStability_JAVA_ONLY_1.Evolving(bytes="no")
public class InterfaceAudience_JAVA_ONLY_1 {
@Retention(RetentionPolicy.RUNTIME)
public @interface Public { String bytes(); }
}
8 changes: 8 additions & 0 deletions tests/pos/i15166/InterfaceStability_JAVA_ONLY_1.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@InterfaceAudience_JAVA_ONLY_1.Public(bytes="yes")
public class InterfaceStability_JAVA_ONLY_1 {
@Retention(RetentionPolicy.RUNTIME)
public @interface Evolving { String bytes(); }
}
4 changes: 4 additions & 0 deletions tests/pos/i15166/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// scalac: -Xfatal-warnings
object Test {
val x: InterfaceAudience_JAVA_ONLY_1.Public = ???
}

0 comments on commit e4b1cfe

Please sign in to comment.