summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/backend
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2016-03-31 16:26:45 -0700
committerAdriaan Moors <adriaan.moors@typesafe.com>2016-03-31 16:26:45 -0700
commit96f230a0e9c254c45dc91c71b5929639e6add1f0 (patch)
tree8f4942f5bb5ed348424664367384543c5160d50b /src/compiler/scala/tools/nsc/backend
parent5654ebddb63d078f9f79dcf84fbb8489030136f6 (diff)
parente4529ca2e0091ec137c791419ae08c8da8e0aecf (diff)
downloadscala-96f230a0e9c254c45dc91c71b5929639e6add1f0.tar.gz
scala-96f230a0e9c254c45dc91c71b5929639e6add1f0.tar.bz2
scala-96f230a0e9c254c45dc91c71b5929639e6add1f0.zip
Merge pull request #5059 from lrytz/t9702
SI-9702 Fix backend crash with classOf[T] annotation argument
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala11
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala60
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala33
3 files changed, 52 insertions, 52 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index 08b5a0afa1..a4d08cb123 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -469,13 +469,10 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
case NullTag => emit(asm.Opcodes.ACONST_NULL)
case ClazzTag =>
- val toPush: BType = {
- typeToBType(const.typeValue) match {
- case kind: PrimitiveBType => boxedClassOfPrimitive(kind)
- case kind => kind
- }
- }
- mnode.visitLdcInsn(toPush.toASMType)
+ val tp = typeToBType(const.typeValue)
+ // classOf[Int] is transformed to Integer.TYPE by CleanUp
+ assert(!tp.isPrimitive, s"expected class type in classOf[T], found primitive type $tp")
+ mnode.visitLdcInsn(tp.toASMType)
case EnumTag =>
val sym = const.symbolValue
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
index 807e0cc72f..a2ccce9d21 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeHelpers.scala
@@ -597,17 +597,6 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
val classSym = if (sym.isJavaDefined && sym.isModuleClass) exitingPickler(sym.linkedClassOfClass) else sym
classBTypeFromSymbol(classSym).internalName
}
-
- /**
- * The jvm descriptor of a type.
- */
- final def descriptor(t: Type): String = typeToBType(t).descriptor
-
- /**
- * The jvm descriptor for a symbol.
- */
- final def descriptor(sym: Symbol): String = classBTypeFromSymbol(sym).descriptor
-
} // end of trait BCInnerClassGen
trait BCAnnotGen extends BCInnerClassGen {
@@ -616,6 +605,35 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
private lazy val AnnotationRetentionPolicyClassValue = AnnotationRetentionPolicyModule.tpe.member(TermName("CLASS"))
private lazy val AnnotationRetentionPolicyRuntimeValue = AnnotationRetentionPolicyModule.tpe.member(TermName("RUNTIME"))
+ /**
+ * Annotations are not processed by the compilation pipeline like ordinary trees. Instead, the
+ * typer extracts them into [[AnnotationInfo]] objects which are attached to the corresponding
+ * symbol (sym.annotations) or type (as an AnnotatedType, eliminated by erasure).
+ *
+ * For Scala annotations this is OK: they are stored in the pickle and ignored by the backend.
+ * Java annoations on the other hand are additionally emitted to the classfile in Java's format.
+ *
+ * This means that [[Type]] instances within an AnnotaionInfo reach the backend non-erased. Examples:
+ * - @(javax.annotation.Resource @annotation.meta.getter) val x = 0
+ * Here, annotationInfo.atp is an AnnotatedType.
+ * - @SomeAnnotation[T] val x = 0
+ * In principle, the annotationInfo.atp is a non-erased type ref. However, this cannot
+ * actually happen because Java annotations cannot be generic.
+ * - @javax.annotation.Resource(`type` = classOf[List[_]]) val x = 0
+ * The annotationInfo.assocs contains a LiteralAnnotArg(Constant(tp)) where tp is the
+ * non-erased existential type.
+ */
+ def erasedType(tp: Type): Type = enteringErasure {
+ // make sure we don't erase value class references to the type that the value class boxes
+ // this is basically the same logic as in erasure's preTransform, case Literal(classTag).
+ tp.dealiasWiden match {
+ case tr @ TypeRef(_, clazz, _) if clazz.isDerivedValueClass => erasure.scalaErasure.eraseNormalClassRef(tr)
+ case tpe => erasure.erasure(tpe.typeSymbol)(tpe)
+ }
+ }
+
+ def descriptorForErasedType(tp: Type): String = typeToBType(erasedType(tp)).descriptor
+
/** Whether an annotation should be emitted as a Java annotation
* .initialize: if 'annot' is read from pickle, atp might be uninitialized
*/
@@ -652,7 +670,6 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
ca(idx) = b.asInstanceOf[Char]
idx += 1
}
-
ca
}
@@ -715,9 +732,10 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
case StringTag =>
assert(const.value != null, const) // TODO this invariant isn't documented in `case class Constant`
av.visit(name, const.stringValue) // `stringValue` special-cases null, but that execution path isn't exercised for a const with StringTag
- case ClazzTag => av.visit(name, typeToBType(const.typeValue).toASMType)
+ case ClazzTag =>
+ av.visit(name, typeToBType(erasedType(const.typeValue)).toASMType)
case EnumTag =>
- val edesc = descriptor(const.tpe) // the class descriptor of the enumeration class.
+ val edesc = descriptorForErasedType(const.tpe) // the class descriptor of the enumeration class.
val evalue = const.symbolValue.name.toString // value the actual enumeration value.
av.visitEnum(name, edesc, evalue)
}
@@ -742,7 +760,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
case NestedAnnotArg(annInfo) =>
val AnnotationInfo(typ, args, assocs) = annInfo
assert(args.isEmpty, args)
- val desc = descriptor(typ) // the class descriptor of the nested annotation class
+ val desc = descriptorForErasedType(typ) // the class descriptor of the nested annotation class
val nestedVisitor = av.visitAnnotation(name, desc)
emitAssocs(nestedVisitor, assocs)
}
@@ -767,7 +785,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
for(annot <- annotations; if shouldEmitAnnotation(annot)) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
- val av = cw.visitAnnotation(descriptor(typ), isRuntimeVisible(annot))
+ val av = cw.visitAnnotation(descriptorForErasedType(typ), isRuntimeVisible(annot))
emitAssocs(av, assocs)
}
}
@@ -779,7 +797,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
for(annot <- annotations; if shouldEmitAnnotation(annot)) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
- val av = mw.visitAnnotation(descriptor(typ), isRuntimeVisible(annot))
+ val av = mw.visitAnnotation(descriptorForErasedType(typ), isRuntimeVisible(annot))
emitAssocs(av, assocs)
}
}
@@ -791,7 +809,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
for(annot <- annotations; if shouldEmitAnnotation(annot)) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
- val av = fw.visitAnnotation(descriptor(typ), isRuntimeVisible(annot))
+ val av = fw.visitAnnotation(descriptorForErasedType(typ), isRuntimeVisible(annot))
emitAssocs(av, assocs)
}
}
@@ -806,7 +824,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
annot <- annots) {
val AnnotationInfo(typ, args, assocs) = annot
assert(args.isEmpty, args)
- val pannVisitor: asm.AnnotationVisitor = jmethod.visitParameterAnnotation(idx, descriptor(typ), isRuntimeVisible(annot))
+ val pannVisitor: asm.AnnotationVisitor = jmethod.visitParameterAnnotation(idx, descriptorForErasedType(typ), isRuntimeVisible(annot))
emitAssocs(pannVisitor, assocs)
}
}
@@ -990,7 +1008,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
mirrorMethod.visitCode()
- mirrorMethod.visitFieldInsn(asm.Opcodes.GETSTATIC, moduleName, strMODULE_INSTANCE_FIELD, descriptor(module))
+ mirrorMethod.visitFieldInsn(asm.Opcodes.GETSTATIC, moduleName, strMODULE_INSTANCE_FIELD, classBTypeFromSymbol(module).descriptor)
var index = 0
for(jparamType <- paramJavaTypes) {
@@ -1051,7 +1069,7 @@ abstract class BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
def getExceptions(excs: List[AnnotationInfo]): List[String] = {
for (ThrownException(tp) <- excs.distinct)
yield {
- val erased = enteringErasure(erasure.erasure(tp.typeSymbol)(tp))
+ val erased = erasedType(tp)
internalName(erased.typeSymbol)
}
}
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
index 85563be428..759b0a615a 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BTypesFromSymbols.scala
@@ -177,7 +177,7 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
/**
* When compiling Array.scala, the type parameter T is not erased and shows up in method
- * signatures, e.g. `def apply(i: Int): T`. A TyperRef to T is replaced by ObjectReference.
+ * signatures, e.g. `def apply(i: Int): T`. A TypeRef for T is replaced by ObjectRef.
*/
def nonClassTypeRefToBType(sym: Symbol): ClassBType = {
assert(sym.isType && isCompilingArray, sym)
@@ -190,39 +190,24 @@ class BTypesFromSymbols[G <: Global](val global: G) extends BTypes {
case TypeRef(_, sym, _) => primitiveOrClassToBType(sym) // Common reference to a type such as scala.Int or java.lang.String
case ClassInfoType(_, _, sym) => primitiveOrClassToBType(sym) // We get here, for example, for genLoadModule, which invokes typeToBType(moduleClassSymbol.info)
- /* AnnotatedType should (probably) be eliminated by erasure. However we know it happens for
- * meta-annotated annotations (@(ann @getter) val x = 0), so we don't emit a warning.
- * The type in the AnnotationInfo is an AnnotatedTpe. Tested in jvm/annotations.scala.
- */
- case a @ AnnotatedType(_, t) =>
- debuglog(s"typeKind of annotated type $a")
- typeToBType(t)
-
- /* ExistentialType should (probably) be eliminated by erasure. We know they get here for
- * classOf constants:
- * class C[T]
- * class T { final val k = classOf[C[_]] }
- */
- case e @ ExistentialType(_, t) =>
- debuglog(s"typeKind of existential type $e")
- typeToBType(t)
-
/* The cases below should probably never occur. They are kept for now to avoid introducing
* new compiler crashes, but we added a warning. The compiler / library bootstrap and the
* test suite don't produce any warning.
*/
case tp =>
- currentUnit.warning(tp.typeSymbol.pos,
+ warning(tp.typeSymbol.pos,
s"an unexpected type representation reached the compiler backend while compiling $currentUnit: $tp. " +
"If possible, please file a bug on issues.scala-lang.org.")
tp match {
- case ThisType(ArrayClass) => ObjectRef // was introduced in 9b17332f11 to fix SI-999, but this code is not reached in its test, or any other test
- case ThisType(sym) => classBTypeFromSymbol(sym)
- case SingleType(_, sym) => primitiveOrClassToBType(sym)
- case ConstantType(_) => typeToBType(t.underlying)
- case RefinedType(parents, _) => parents.map(typeToBType(_).asClassBType).reduceLeft((a, b) => a.jvmWiseLUB(b).get)
+ case ThisType(ArrayClass) => ObjectRef // was introduced in 9b17332f11 to fix SI-999, but this code is not reached in its test, or any other test
+ case ThisType(sym) => classBTypeFromSymbol(sym)
+ case SingleType(_, sym) => primitiveOrClassToBType(sym)
+ case ConstantType(_) => typeToBType(t.underlying)
+ case RefinedType(parents, _) => parents.map(typeToBType(_).asClassBType).reduceLeft((a, b) => a.jvmWiseLUB(b).get)
+ case AnnotatedType(_, t) => typeToBType(t)
+ case ExistentialType(_, t) => typeToBType(t)
}
}
}