summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLex Spoon <lex@lexspoon.org>2007-05-21 15:49:37 +0000
committerLex Spoon <lex@lexspoon.org>2007-05-21 15:49:37 +0000
commitfe55fa336be15afe509fbc7096e8cf51026cbfd9 (patch)
tree6d47073ccecfaacf588e017e22551c92a3d055d0 /src
parent22a8618b48e945323723755525bbdeb97c63da3e (diff)
downloadscala-fe55fa336be15afe509fbc7096e8cf51026cbfd9.tar.gz
scala-fe55fa336be15afe509fbc7096e8cf51026cbfd9.tar.bz2
scala-fe55fa336be15afe509fbc7096e8cf51026cbfd9.zip
Annotations clean up, including:
- AnnotationInfo has no type parameter. It always has a parse tree, and sometimes has a constant. - SymbolReifier is separated from LiftCode for independent use - reification into reflect.* structures handles more cases - unreify is added, for enough cases that annotations work
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/ast/NodePrinters.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala40
-rw-r--r--src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala12
-rw-r--r--src/compiler/scala/tools/nsc/doc/ModelToXML.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala149
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Constants.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolTable.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala13
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala10
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala4
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/PickleBuffer.scala3
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala26
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala33
-rw-r--r--src/compiler/scala/tools/nsc/transform/LiftCode.scala80
-rw-r--r--src/compiler/scala/tools/nsc/transform/SymbolReifier.scala172
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala67
17 files changed, 454 insertions, 165 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
index f114426d3e..31cc368ec8 100644
--- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
+++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala
@@ -41,7 +41,7 @@ abstract class NodePrinters {
if (comma) buf.append(",")
buf.append(EOL)
}
- def annotationInfoToString(attr: AnnotationInfo[Constant]) = {
+ def annotationInfoToString(attr: AnnotationInfo) = {
val str = new StringBuilder
str.append(attr.atp.toString())
if (!attr.args.isEmpty)
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index cd7096283f..9ee4404cc9 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -151,7 +151,7 @@ abstract class GenJVM extends SubComponent {
case AnnotationInfo(CloneableAttr, _, _) =>
parents = parents ::: List(CloneableClass.tpe)
case AnnotationInfo(SerialVersionUID, value :: _, _) =>
- serialVUID = Some(value.longValue)
+ serialVUID = Some(value.constant.get.longValue)
case AnnotationInfo(RemoteAttr, _, _) =>
parents = parents ::: List(RemoteInterface.tpe)
remoteClass = true
@@ -215,7 +215,9 @@ abstract class GenJVM extends SubComponent {
buf.putShort(0xbaba.toShort)
for (val AnnotationInfo(ThrowsAttr, List(exc), _) <- excs.removeDuplicates) {
- buf.putShort(cpool.addClass(javaName(exc.typeValue.symbol)).shortValue)
+ buf.putShort(
+ cpool.addClass(
+ javaName(exc.constant.get.typeValue.symbol)).shortValue)
nattr = nattr + 1
}
@@ -224,7 +226,7 @@ abstract class GenJVM extends SubComponent {
addAttribute(jmethod, nme.ExceptionsATTR, buf)
}
- private def emitAttributes(buf: ByteBuffer, attributes: List[AnnotationInfo[Constant]]): Int = {
+ private def emitAttributes(buf: ByteBuffer, attributes: List[AnnotationInfo]): Int = {
val cpool = jclass.getConstantPool()
def emitElement(const: Constant): Unit = const.tag match {
@@ -272,11 +274,12 @@ abstract class GenJVM extends SubComponent {
var nattr = 0
val pos = buf.position()
- // put some radom value; the actual number of annotations is determined at the end
+ // put some random value; the actual number of annotations is determined at the end
buf.putShort(0xbaba.toShort)
- for (val AnnotationInfo(typ, consts, nvPairs) <- attributes;
- typ.symbol isNonBottomSubClass definitions.ClassfileAnnotationClass) {
+ for (attrib@AnnotationInfo(typ, consts, nvPairs) <- attributes;
+ if attrib.isConstant;
+ if typ.symbol isNonBottomSubClass definitions.ClassfileAnnotationClass) {
nattr = nattr + 1
val jtype = javaType(typ)
buf.putShort(cpool.addUtf8(jtype.getSignature()).toShort)
@@ -284,11 +287,11 @@ abstract class GenJVM extends SubComponent {
buf.putShort((consts.length + nvPairs.length).toShort)
if (!consts.isEmpty) {
buf.putShort(cpool.addUtf8("value").toShort)
- emitElement(consts.head)
+ emitElement(consts.head.constant.get)
}
for (val (name, value) <- nvPairs) {
buf.putShort(cpool.addUtf8(name.toString).toShort)
- emitElement(value)
+ emitElement(value.constant.get)
}
}
@@ -297,20 +300,23 @@ abstract class GenJVM extends SubComponent {
nattr
}
- def addAnnotations(jmember: JMember, attributes: List[AnnotationInfo[Constant]]): Unit = {
- if (attributes.isEmpty) return
+ def addAnnotations(jmember: JMember, attributes: List[AnnotationInfo]): Unit = {
+ val toEmit = attributes.filter(.isConstant)
+
+ if (toEmit.isEmpty) return
val buf: ByteBuffer = ByteBuffer.allocate(2048)
- emitAttributes(buf, attributes)
+ emitAttributes(buf, toEmit)
addAttribute(jmember, nme.RuntimeAnnotationATTR, buf)
}
- def addParamAnnotations(pattrss: List[List[AnnotationInfo[Constant]]]): Unit = {
- val attributes = for (val attrs <- pattrss) yield
- for (val attr @ AnnotationInfo(tpe, _, _) <- attrs;
- tpe.symbol isNonBottomSubClass definitions.ClassfileAnnotationClass) yield attr;
+ def addParamAnnotations(pattrss: List[List[AnnotationInfo]]): Unit = {
+ val attributes = for (attrs <- pattrss) yield
+ for (attr @ AnnotationInfo(tpe, _, _) <- attrs;
+ if attr.isConstant;
+ if tpe.symbol isNonBottomSubClass definitions.ClassfileAnnotationClass) yield attr;
if (attributes.forall(.isEmpty)) return;
val buf: ByteBuffer = ByteBuffer.allocate(2048)
@@ -411,8 +417,8 @@ abstract class GenJVM extends SubComponent {
(m.symbol.attributes contains AnnotationInfo(RemoteAttr, Nil, Nil))) &&
jmethod.isPublic() && !forCLDC)
{
- m.symbol.attributes =
- AnnotationInfo(ThrowsAttr, List(Constant(RemoteException)), List()) :: m.symbol.attributes;
+ val ainfo = AnnotationInfo(ThrowsAttr, List(new AnnotationArgument(Constant(RemoteException))), List())
+ m.symbol.attributes = ainfo :: m.symbol.attributes;
}
if (!jmethod.isAbstract()) {
diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
index 6c6835bb6a..4eb8f987da 100644
--- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
+++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala
@@ -293,12 +293,15 @@ abstract class GenMSIL extends SubComponent {
log("Could not find pickle information for " + sym)
}
- def addAttributes(member: ICustomAttributeSetter, attributes: List[AnnotationInfo[Constant]]): Unit = {
+ def addAttributes(member: ICustomAttributeSetter, attributes: List[AnnotationInfo]): Unit = {
return // FIXME
if (settings.debug.value)
log("creating attributes: " + attributes + " for member : " + member)
- for (AnnotationInfo(typ, consts, nvPairs) <- attributes /* !typ.symbol.hasFlag(Flags.JAVA) */ ) {
+ for (attr@ AnnotationInfo(typ, annArgs, nvPairs) <- attributes ;
+ if attr.isConstant)
+ /* !typ.symbol.hasFlag(Flags.JAVA) */
+ {
// assert(consts.length <= 1,
// "too many constant arguments for attribute; "+consts.toString())
@@ -317,7 +320,10 @@ abstract class GenMSIL extends SubComponent {
// otehr way than GetConstructors()(0) to get the constructor, if there's
// no constructor symbol available.
- val args: Array[Byte] = getAttributeArgs(consts, nvPairs)
+ val args: Array[Byte] =
+ getAttributeArgs(
+ annArgs map (.constant.get),
+ (for((n,v) <- nvPairs) yield (n, v.constant.get)))
member.SetCustomAttribute(constr, args)
}
}
diff --git a/src/compiler/scala/tools/nsc/doc/ModelToXML.scala b/src/compiler/scala/tools/nsc/doc/ModelToXML.scala
index 234b640546..31c59cd18a 100644
--- a/src/compiler/scala/tools/nsc/doc/ModelToXML.scala
+++ b/src/compiler/scala/tools/nsc/doc/ModelToXML.scala
@@ -245,12 +245,12 @@ trait ModelToXML extends ModelExtractor {
</tr>
def attrsFor(entity: Entity)(implicit from: Frame): NodeSeq = {
- def attrFor(attr: AnnotationInfo[Constant]): Node = {
+ def attrFor(attr: AnnotationInfo): Node = {
val buf = new StringBuilder
val AnnotationInfo(tpe, args, nvPairs) = attr
val name = link(decode(tpe.symbol))
if (!args.isEmpty)
- buf.append(args.map(.escapedStringValue).mkString("(", ",", ")"))
+ buf.append(args.mkString("(", ",", ")"))
if (!nvPairs.isEmpty)
for (((name, value), index) <- nvPairs.zipWithIndex) {
if (index > 0)
diff --git a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala
new file mode 100644
index 0000000000..97667a5dc3
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala
@@ -0,0 +1,149 @@
+package scala.tools.nsc.symtab
+import scala.tools.nsc.transform.SymbolReifier
+import util._
+
+/** AnnotationInfo and its helpers */
+trait AnnotationInfos {
+ self : SymbolTable =>
+
+
+ /** Convert a reflect tree to a Constant, if possible */
+ private def refltree2cons(tree: reflect.Tree): Option[Constant] =
+ tree match {
+ case reflect.Literal(v) => Some(Constant(v))
+
+ case reflect.Apply(
+ reflect.TypeApply(
+ reflect.Select(_,
+ reflect.Method(
+ "scala.Array.apply",
+ reflect.PolyType(_, _,
+ reflect.MethodType(_, reflect.AppliedType(arrayType,_))))),
+ List(elemType)),
+ members) =>
+
+ refltrees2consArray(
+ members,
+ reflect.AppliedType(arrayType, List(elemType)))
+
+
+ case reflect.Apply(
+ reflect.Select(_,
+ reflect.Method(
+ "scala.Array.apply",
+ reflect.MethodType(_, arrayType))),
+ members) =>
+
+ refltrees2consArray(members, arrayType)
+
+ case tree =>
+ //println("could not convert: " + tree);
+ None
+ }
+
+ private object symbolReifier extends SymbolReifier {
+ val symbols: AnnotationInfos.this.type = AnnotationInfos.this
+ }
+
+ /** Convert a sequence of trees to an array type,
+ * if all of the array elements are constants.
+ * Use arrayType as type of the resulting constant.
+ */
+ private def refltrees2consArray(
+ trees: Seq[reflect.Tree],
+ arrayType: reflect.Type)
+ : Option[Constant] =
+ {
+ // println("arrayType is " + arrayType + " (" +
+ // symbolReifier.unreify(arrayType) + ")")
+
+ val mems = trees.map(refltree2cons)
+
+ if(mems.exists(.isEmpty))
+ None
+ else
+ Some(new ArrayConstant(
+ mems.map(.get).toArray,
+ symbolReifier.unreify(arrayType)))
+ }
+
+
+ /** Convert a constant to an equivalent reflect tree. */
+ private def cons2refltree(cons: Constant): reflect.Tree = {
+ import reflect._
+
+ (cons: @unchecked) match {
+ case acons:ArrayConstant =>
+ val elems = acons.arrayValue.toList
+ val arrayType = symbolReifier.reify(cons.tpe)
+ val elemType: reflect.Type = arrayType match {
+ case AppliedType(_, List(et)) => et
+ case _ =>
+ assert(false, "array type is not an array type");
+ reflect.NoType
+ }
+ val elemTrees = elems map cons2refltree
+
+ val arrayObject = reflect.This(reflect.Class("scala.Array"))
+
+ // The following two gigantic trees were found by printing
+ // out what the reifier makes. If the reifier changes, they
+ // should be updated.
+ if(symbolReifier.unreify(elemType) <:< definitions.AnyValClass.tpe)
+ Apply(Select(Select(Ident(Field("scala",PrefixedType(reflect.ThisType(RootSymbol),Class("scala")))),Field("scala.Array",PrefixedType(reflect.ThisType(Class("scala")),Class("scala.Array")))),Method("scala.Array.apply",reflect.MethodType(List(AppliedType(PrefixedType(reflect.ThisType(Class("scala")),Class("scala.<repeated>")),List(PrefixedType(reflect.ThisType(Class("scala")),Class("scala.Int"))))),AppliedType(PrefixedType(reflect.ThisType(Class("scala")),Class("scala.Array")),
+ List(elemType))))), elemTrees)
+
+
+ else
+ Apply(TypeApply(Select(Select(Ident(Field("scala",PrefixedType(reflect.ThisType(RootSymbol),Class("scala")))),Field("scala.Array",PrefixedType(reflect.ThisType(Class("scala")),Class("scala.Array")))),Method("scala.Array.apply",reflect.PolyType(List(reflect.NoSymbol),List((PrefixedType(reflect.ThisType(Class("scala")),Class("scala.Nothing")),PrefixedType(reflect.ThisType(Class("scala")),TypeField("scala.AnyRef",PrefixedType(reflect.ThisType(Class("java.lang")),Class("java.lang.Object")))))),reflect.MethodType(List(AppliedType(PrefixedType(reflect.ThisType(Class("scala")),Class("scala.<repeated>")),List(PrefixedType(reflect.NoType,reflect.NoSymbol)))),AppliedType(PrefixedType(reflect.ThisType(Class("scala")),Class("scala.Array")),List(PrefixedType(reflect.NoType,reflect.NoSymbol))))))),
+ List(elemType)), elemTrees)
+
+ case Constant(value) => reflect.Literal(value)
+ }
+ }
+
+
+
+
+
+ /** An argument to an annotation. It includes a parse tree,
+ * and it includes a compile-time constant for the tree if possible.
+ */
+ class AnnotationArgument(val tree: reflect.Tree)
+ {
+ def this(cons: Constant) = this(cons2refltree(cons))
+
+//println("tree is: " + tree)
+
+ val constant: Option[Constant] = refltree2cons(tree)
+
+ def isConstant = !constant.isEmpty
+
+ override def toString: String =
+ constant match {
+ case Some(cons) => cons.escapedStringValue
+ case None => tree.toString
+ }
+ }
+
+ /** Typed information about an annotation. It can be attached to
+ * either a symbol or an annotated type.
+ */
+ case class AnnotationInfo(
+ atp: Type,
+ args: List[AnnotationArgument],
+ assocs: List[(Name, AnnotationArgument)])
+ {
+ override def toString: String =
+ atp +
+ (if (args.isEmpty) ""
+ else args.mkString("(", ", ", ")")) +
+ (if (assocs.isEmpty) ""
+ else (assocs map { case (x, y) => x+" = "+y } mkString ("{", ", ", "}")))
+
+ /** Check whether all arguments and assocations are constants */
+ def isConstant =
+ ((args forall (.isConstant)) &&
+ (assocs map (._2) forall (.isConstant)))
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/symtab/Constants.scala b/src/compiler/scala/tools/nsc/symtab/Constants.scala
index e622d85d47..6926edf826 100644
--- a/src/compiler/scala/tools/nsc/symtab/Constants.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Constants.scala
@@ -232,5 +232,4 @@ trait Constants {
extends Constant(arrayValue) {
override def toString() = arrayValue.mkString("Constant(", "," , ")")
}
-
}
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
index c68d2dfee3..c066492fe1 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolTable.scala
@@ -15,6 +15,7 @@ abstract class SymbolTable extends Names
with Constants
with InfoTransformers
with StdNames
+ with AnnotationInfos
{
def settings: Settings
def rootLoader: LazyType
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index c23477e3d0..c1d2d222ea 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -80,7 +80,7 @@ trait Symbols {
else -1
}
- var attributes: List[AnnotationInfo[Constant]] = List()
+ var attributes: List[AnnotationInfo] = List()
var privateWithin: Symbol = _
@@ -554,7 +554,7 @@ trait Symbols {
def typeParams: List[Symbol] =
if (isMonomorphicType) List() else { rawInfo.load(this); rawInfo.typeParams }
- def getAttributes(clazz: Symbol): List[AnnotationInfo[Constant]] =
+ def getAttributes(clazz: Symbol): List[AnnotationInfo] =
attributes.filter(.atp.symbol.isNonBottomSubClass(clazz))
/** Reset symbol to initial state
@@ -1347,14 +1347,7 @@ trait Symbols {
def cloneSymbolImpl(owner: Symbol): Symbol = throw new Error()
}
- case class AnnotationInfo[+T](atp: Type, args: List[T], assocs: List[(Name, T)]) {
- override def toString: String =
- atp +
- (if (args.isEmpty) ""
- else args.mkString("(", ", ", ")")) +
- (if (assocs.isEmpty) ""
- else (assocs map { case (x, y) => x+" = "+y } mkString ("{", ", ", "}")))
- }
+
def cloneSymbols(syms: List[Symbol]): List[Symbol] = {
val syms1 = syms map (.cloneSymbol)
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala
index 07fb96923b..9cfec0d6e6 100644
--- a/src/compiler/scala/tools/nsc/symtab/Types.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Types.scala
@@ -129,7 +129,7 @@ trait Types {
override def isComplete = tp.isComplete
override def complete(sym: Symbol) = tp.complete(sym)
override def load(sym: Symbol): unit = tp.load(sym)
- override def withAttributes(attribs: List[AnnotationInfo[Any]]) = tp.withAttributes(attribs)
+ override def withAttributes(attribs: List[AnnotationInfo]) = tp.withAttributes(attribs)
override def withoutAttributes = tp.withoutAttributes
}
@@ -603,10 +603,10 @@ trait Types {
}
/** Add an attribute to this type */
- def withAttribute(attrib: AnnotationInfo[Any]) = withAttributes(List(attrib))
+ def withAttribute(attrib: AnnotationInfo) = withAttributes(List(attrib))
/** Add a number of attributes to this type */
- def withAttributes(attribs: List[AnnotationInfo[Any]]): Type =
+ def withAttributes(attribs: List[AnnotationInfo]): Type =
attribs match {
case Nil => this
case _ => AnnotatedType(attribs, this)
@@ -1445,7 +1445,7 @@ A type's symbol should never be inspected directly.
* to the core compiler, but can be observed by type-system plugins. The
* core compiler does take care to propagate attributes and to save them
* in the symbol tables of object files. */
- case class AnnotatedType(attributes: List[AnnotationInfo[Any]], tp: Type) extends TypeProxy {
+ case class AnnotatedType(attributes: List[AnnotationInfo], tp: Type) extends TypeProxy {
override def toString(): String = {
val attString =
if (attributes.isEmpty)
@@ -1458,7 +1458,7 @@ A type's symbol should never be inspected directly.
/** Add a number of attributes to this type */
- override def withAttributes(attribs: List[AnnotationInfo[Any]]): Type =
+ override def withAttributes(attribs: List[AnnotationInfo]): Type =
AnnotatedType(attribs:::this.attributes, this)
/** Remove any attributes from this type */
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 92b54344bf..d991a2e601 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -704,10 +704,10 @@ abstract class ClassfileParser {
val attrNameIndex = in.nextChar
val attrType = pool.getType(attrNameIndex)
val nargs = in.nextChar
- val nvpairs = new ListBuffer[(Name,Constant)]
+ val nvpairs = new ListBuffer[(Name,AnnotationArgument)]
for (i <- 0 until nargs) {
val name = pool.getName(in.nextChar)
- nvpairs += (name, parseTaggedConstant)
+ nvpairs += ((name, new AnnotationArgument(parseTaggedConstant)))
}
sym.attributes = AnnotationInfo(attrType, List(), nvpairs.toList) :: sym.attributes
}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/PickleBuffer.scala b/src/compiler/scala/tools/nsc/symtab/classfile/PickleBuffer.scala
index f890eebaa2..859a42804f 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/PickleBuffer.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/PickleBuffer.scala
@@ -83,6 +83,9 @@ class PickleBuffer(data: Array[byte], from: int, to: int) {
// -- Basic input routines --------------------------------------------
+ /** Peek at the current byte without moving the read index */
+ def peekByte(): int = bytes(readIndex)
+
/** Read a byte */
def readByte(): int = {
val x = bytes(readIndex); readIndex += 1; x
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
index 3aca840982..c499679961 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -4,7 +4,6 @@
*/
// $Id$
-
package scala.tools.nsc.symtab.classfile
import java.lang.{Float, Double}
@@ -273,14 +272,14 @@ abstract class Pickler extends SubComponent {
children foreach putSymbol
}
- private def putAnnotation(sym: Symbol, attr: AnnotationInfo[Constant]): unit = {
+ private def putAnnotation(sym: Symbol, attr: AnnotationInfo): unit = {
assert(putEntry((sym, attr)))
putType(attr.atp)
- for (c <- attr.args) putConstant(c)
- for ((name, c) <- attr.assocs) { putEntry(name); putConstant(c) }
+ for (c <- attr.args) putTreeOrConstant(c)
+ for ((name, c) <- attr.assocs) { putEntry(name); putTreeOrConstant(c) }
}
- private def putAnnotation(annot: AnnotationInfo[Any]): unit =
+ private def putAnnotation(annot: AnnotationInfo): unit =
if(putEntry(annot)) {
val AnnotationInfo(tpe, args, assocs) = annot
putType(tpe)
@@ -288,7 +287,7 @@ abstract class Pickler extends SubComponent {
for ((name, rhs) <- assocs) { putEntry(name); putTreeOrConstant(rhs) }
}
- private def putTreeOrConstant(x: Any) {
+ private def putTreeOrConstant(x: AnyRef) {
x match {
case c:Constant => putConstant(c)
case tree:reflect.Tree => putTree(tree)
@@ -297,7 +296,7 @@ abstract class Pickler extends SubComponent {
}
}
- private def putAnnotations(annots: List[AnnotationInfo[Any]]): unit =
+ private def putAnnotations(annots: List[AnnotationInfo]): unit =
annots foreach putAnnotation
// Phase 2 methods: Write all entries to byte array ------------------------------
@@ -406,8 +405,8 @@ abstract class Pickler extends SubComponent {
case (target: Symbol, attr @ AnnotationInfo(atp, args, assocs)) =>
writeRef(target)
writeRef(atp)
- for (c <- args) writeRef(c.asInstanceOf[Constant])
- for ((name, c) <- assocs) { writeRef(name); writeRef(c.asInstanceOf[Constant]) }
+ for (c <- args) writeRef(c)
+ for ((name, c) <- assocs) { writeRef(name); writeRef(c) }
ATTRIBUTE
case (target: Symbol, children: List[_]) =>
writeRef(target)
@@ -434,7 +433,7 @@ abstract class Pickler extends SubComponent {
case reflect.TypeApply(fun, args) =>
writeNat(TYPEAPPLYtree)
writeRef(fun)
- writeRef(args)
+ writeRefs(args)
REFLTREE
case reflect.Function(params, body) =>
writeNat(FUNCTIONtree)
@@ -596,14 +595,15 @@ abstract class Pickler extends SubComponent {
REFLSYM
case reflect.LabelSymbol(name) =>
writeNat(LABELSYMBOLrsym)
+ writeRef(name)
REFLSYM
case AnnotationInfo(target, args, assocs) =>
writeRef(target)
writeNat(args.length)
- for (tree <- args) writeRef(tree.asInstanceOf[reflect.Tree])
- for ((name, tree) <- assocs) {
+ for (arg <- args) writeRef(arg)
+ for ((name, arg) <- assocs) {
writeRef(name);
- writeRef(tree.asInstanceOf[reflect.Tree])
+ writeRef(arg)
}
ATTRIBTREE
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
index 5e3c4a5ce0..70735b79ff 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala
@@ -292,6 +292,19 @@ abstract class UnPickler {
}
}
+ /** Read an annotation argument. It can be either a Constant or
+ * a reflect.Tree.
+ */
+ private def readAnnotationArg(): AnnotationArgument = {
+ if (peekByte() == REFLTREE) {
+ val tree = readReflTree()
+ new AnnotationArgument(tree)
+ } else {
+ val const = readConstant()
+ new AnnotationArgument(const)
+ }
+ }
+
/** Read an attribute and store in referenced symbol */
private def readAnnotation(): AnyRef = {
val tag = readByte()
@@ -299,12 +312,14 @@ abstract class UnPickler {
val target = readSymbolRef()
if (tag == ATTRIBUTE) {
val attrType = readTypeRef()
- val args = new ListBuffer[Constant]
- val assocs = new ListBuffer[(Name, Constant)]
+ val args = new ListBuffer[AnnotationArgument]
+ val assocs = new ListBuffer[(Name, AnnotationArgument)]
while (readIndex != end) {
val argref = readNat()
- if (isNameEntry(argref)) assocs += (at(argref, readName), readConstantRef())
- else args += at(argref, readConstant)
+ if (isNameEntry(argref))
+ assocs += (at(argref, readName), readAnnotationArgRef)
+ else
+ args += at(argref, readAnnotationArg)
}
val attr = AnnotationInfo(attrType, args.toList, assocs.toList)
target.attributes = attr :: target.attributes
@@ -497,7 +512,7 @@ abstract class UnPickler {
}
/** Read an annotation with reflect.Tree's */
- private def readTreeAttrib(): AnnotationInfo[reflect.Tree] = {
+ private def readTreeAttrib(): AnnotationInfo = {
val tag = readByte()
if(tag != ATTRIBTREE)
errorBadSignature("tree-based annotation expected (" + tag + ")")
@@ -505,11 +520,11 @@ abstract class UnPickler {
val target = readTypeRef()
val numargs = readNat()
- val args = times(numargs, readReflTreeRef)
+ val args = times(numargs, readAnnotationArgRef)
val assocs =
until(end, {() =>
val name = readNameRef()
- val tree = readReflTreeRef()
+ val tree = readAnnotationArgRef()
(name,tree)})
AnnotationInfo(target, args, assocs)
}
@@ -519,13 +534,15 @@ abstract class UnPickler {
private def readSymbolRef(): Symbol = at(readNat(), readSymbol)
private def readTypeRef(): Type = at(readNat(), readType)
private def readConstantRef(): Constant = at(readNat(), readConstant)
+ private def readAnnotationArgRef(): AnnotationArgument =
+ at(readNat(), readAnnotationArg)
private def readReflTreeRef(): reflect.Tree =
at(readNat(), readReflTree)
private def readReflSymbolRef(): reflect.Symbol =
at(readNat(), readReflSymbol)
private def readReflTypeRef(): reflect.Type =
at(readNat(), readReflType)
- private def readTreeAttribRef(): AnnotationInfo[reflect.Tree] =
+ private def readTreeAttribRef(): AnnotationInfo =
at(readNat(), readTreeAttrib)
private def errorBadSignature(msg: String) =
diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala
index 77d0992617..1359eafcf9 100644
--- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala
+++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala
@@ -64,7 +64,12 @@ abstract class LiftCode extends Transform {
super.update(sym,rsym)
}
- class Reifier(env: ReifyEnvironment, currentOwner: reflect.Symbol) {
+
+ class Reifier(env: ReifyEnvironment, currentOwner: reflect.Symbol)
+ extends SymbolReifier
+ {
+ val symbols: global.type = global
+
def reify(tree: Tree): reflect.Tree = tree match {
case Ident(_) =>
@@ -163,72 +168,13 @@ abstract class LiftCode extends Transform {
throw new TypeError("cannot reify tree ("+tree.getClass()+"): " + tree)
}
- private def mkGlobalSymbol(fullname: String, sym: Symbol): reflect.Symbol =
- if (sym.isClass) reflect.Class(fullname)
- else if (sym.isType) reflect.TypeField(fullname, reify(sym.info))
- else if (sym.isMethod) reflect.Method(fullname, reify(sym.info))
- else reflect.Field(fullname, reify(sym.info));
-
- def reify(sym: Symbol): reflect.Symbol = env.get(sym) match {
- case Some(rsym) =>
- rsym
- case None =>
- if (sym.isRoot || sym.isRootPackage || sym.isEmptyPackageClass || sym.isEmptyPackage)
- reflect.RootSymbol
- else if (sym.owner.isTerm)
- reflect.NoSymbol
- else reify(sym.owner) match {
- case reflect.NoSymbol =>
- reflect.NoSymbol;
- case reflect.RootSymbol =>
- mkGlobalSymbol(sym.name.toString(), sym)
- case reflect.Class(ownername) =>
- mkGlobalSymbol(ownername + "." + sym.name, sym)
- case _ =>
- reflect.NoSymbol
- }
- }
-
- var _log_reify_type_ = false
-
- def reify(tp: Type): reflect.Type = tp match {
- case ErrorType =>
- if (_log_reify_type_) println("cannot handle ErrorType"); reflect.NoType
- case WildcardType =>
- if (_log_reify_type_) println("cannot handle WildcardType"); reflect.NoType
- case NoType =>
- if (_log_reify_type_) println("cannot handle NoType"); reflect.NoType
- case NoPrefix =>
- if (_log_reify_type_) println("cannot handle NoPrefix"); reflect.NoType
- case ThisType(sym) =>
- if (_log_reify_type_) println("ThisType ("+sym+")")
- val rsym = reify(sym)
- if (_log_reify_type_) println("reified is "+rsym+" cannot handle ThisType "+tp); reflect.NoType
- case SingleType(pre, sym) =>
- if (_log_reify_type_) println("cannot handle SingleType "+tp); reflect.NoType
- case ConstantType(value) =>
- if (_log_reify_type_) println("cannot handle ConstantType("+value+") "+tp); reflect.NoType
- case TypeRef(pre, sym, args) =>
- if (_log_reify_type_) println("TypeRef! try to handle prefix")
- val rpre = reify(pre)
- if (_log_reify_type_) println("cannot handle TypeRef("+pre+","+sym+","+args+") == "+tp+")"); reflect.NoType
-
- case TypeBounds(lo, hi) =>
- if (_log_reify_type_) println("cannot handle TypeBounds "+tp); reflect.NoType
- case RefinedType(parents, defs) =>
- if (_log_reify_type_) println("cannot handle RefinedType "+tp); reflect.NoType
- case ClassInfoType(parents, defs, clazz) =>
- if (_log_reify_type_) println("cannot handle ClassInfoType "+tp); reflect.NoType
- case MethodType(paramtypes, result) =>
- if (_log_reify_type_) println("cannot handle MethodType "+tp); reflect.NoType
- case PolyType(tparams, result) =>
- if (_log_reify_type_) println("cannot handle PolyType "+tp); reflect.NoType
- case AnnotatedType(attribs, tp) =>
- reify(tp)
- case _ =>
- reflect.NoType
- }
-
+ override def reify(sym: Symbol): reflect.Symbol =
+ env.get(sym) match {
+ case Some(rsym) =>
+ rsym
+ case None =>
+ super.reify(sym)
+ }
}
type InjectEnvironment = ListMap[reflect.Symbol, Name]
diff --git a/src/compiler/scala/tools/nsc/transform/SymbolReifier.scala b/src/compiler/scala/tools/nsc/transform/SymbolReifier.scala
new file mode 100644
index 0000000000..e1fa4f6cfc
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/transform/SymbolReifier.scala
@@ -0,0 +1,172 @@
+package scala.tools.nsc.transform
+import scala.tools.nsc.symtab.SymbolTable
+import scala.reflect
+
+/** Functions to reify (and un-reify) symbols and types.
+ * These can be used with only a symbol table; they do not
+ * need a full compiler.
+ *
+ * @author Gilles Dubochet, Lex Spoon
+ */
+trait SymbolReifier {
+ val symbols: SymbolTable
+ import symbols._
+
+ private def mkGlobalSymbol(fullname: String, sym: Symbol): reflect.Symbol =
+ if (sym.isClass) reflect.Class(fullname)
+ else if (sym.isType) reflect.TypeField(fullname, reify(sym.info))
+ else if (sym.isMethod) reflect.Method(fullname, reify(sym.info))
+ else reflect.Field(fullname, reify(sym.info));
+
+ def reify(sym: Symbol): reflect.Symbol = {
+ if (sym.isRoot || sym.isRootPackage || sym.isEmptyPackageClass || sym.isEmptyPackage)
+ reflect.RootSymbol
+ else if (sym.owner.isTerm)
+ reflect.NoSymbol
+ else reify(sym.owner) match {
+ case reflect.NoSymbol =>
+ reflect.NoSymbol;
+ case reflect.RootSymbol =>
+ mkGlobalSymbol(sym.name.toString(), sym)
+ case reflect.Class(ownername) =>
+ mkGlobalSymbol(ownername + "." + sym.name, sym)
+ case _ =>
+ reflect.NoSymbol
+ }
+ }
+
+ var _log_reify_type_ = true//false
+
+ def reify(tp: Type): reflect.Type = tp match {
+ case ErrorType =>
+ reflect.NoType
+ case WildcardType =>
+ if (_log_reify_type_) println("cannot handle WildcardType")
+ reflect.NoType
+ case NoType =>
+ reflect.NoType
+ case NoPrefix =>
+ reflect.NoType
+ case ThisType(sym) =>
+ val rsym = reify(sym)
+ reflect.ThisType(rsym)
+ case SingleType(pre, sym) =>
+ reflect.SingleType(reify(pre), reify(sym))
+ case ConstantType(value) =>
+ reify(value.tpe)
+ case TypeRef(pre, sym, args) =>
+ val rpre = reify(pre)
+ val rsym = reify(sym)
+ val rargs = args map reify
+ val beforeArgs = reflect.PrefixedType(rpre, rsym)
+ if(rargs.isEmpty)
+ beforeArgs
+ else if(beforeArgs == NoType)
+ beforeArgs
+ else
+ reflect.AppliedType(beforeArgs, rargs)
+ case TypeBounds(lo, hi) =>
+ reflect.TypeBounds(reify(lo), reify(hi))
+ case RefinedType(parents, defs) =>
+ if (_log_reify_type_) println("cannot handle RefinedType "+tp); reflect.NoType
+ case ClassInfoType(parents, defs, clazz) =>
+ if (_log_reify_type_) println("cannot handle ClassInfoType "+tp); reflect.NoType
+ case MethodType(paramtypes, result) =>
+ reflect.MethodType(paramtypes.map(reify), reify(result))
+ case PolyType(tparams, result) =>
+ val boundss =
+ for {
+ param <- tparams
+ TypeBounds(lo,hi) = param.info.bounds
+ } yield (reify(lo), reify(hi))
+
+ reflect.PolyType(
+ tparams.map(reify),
+ boundss,
+ reify(result))
+ case AnnotatedType(attribs, tp) =>
+ reify(tp)
+ case _ =>
+ println("could not reify: " + tp)
+ reflect.NoType
+ }
+
+
+ /** This is woefully incomplete. It is barely enough
+ * to process the types of Constant's .
+ */
+ def unreify(tpe: reflect.Type): Type =
+ tpe match {
+ case reflect.NoPrefix => NoPrefix
+ case reflect.NoType => NoType
+ case reflect.NamedType(fullname) =>
+ //NamedType(fullname)
+ println("NamedType: " + fullname)
+ NoType
+ case reflect.PrefixedType(_, reflect.Class("scala.Array")) =>
+ definitions.ArrayClass.tpe
+ case reflect.PrefixedType(_, reflect.Class("java.lang.String")) =>
+ definitions.StringClass.tpe
+ case reflect.PrefixedType(_, reflect.Class("scala.Unit")) =>
+ definitions.UnitClass.tpe
+ case reflect.PrefixedType(_, reflect.Class("scala.Boolean")) =>
+ definitions.BooleanClass.tpe
+ case reflect.PrefixedType(_, reflect.Class("scala.Byte")) =>
+ definitions.ByteClass.tpe
+ case reflect.PrefixedType(_, reflect.Class("scala.Short")) =>
+ definitions.ShortClass.tpe
+ case reflect.PrefixedType(_, reflect.Class("scala.Int")) =>
+ definitions.IntClass.tpe
+ case reflect.PrefixedType(_, reflect.Class("scala.Long")) =>
+ definitions.LongClass.tpe
+ case reflect.PrefixedType(_, reflect.Class("scala.Float")) =>
+ definitions.FloatClass.tpe
+ case reflect.PrefixedType(_, reflect.Class("scala.Double")) =>
+ definitions.DoubleClass.tpe
+ case reflect.PrefixedType(pre, sym) =>
+ NoType
+ case reflect.SingleType(pre, sym) =>
+ SingleType(unreify(pre), unreify(sym))
+ case reflect.ThisType(clazz) =>
+ ThisType(unreify(clazz))
+ case reflect.AppliedType(tpe, args) =>
+ val untpe = unreify(tpe)
+ if (untpe == NoType)
+ NoType
+ else
+ appliedType(untpe, args.map(unreify))
+ case reflect.TypeBounds(lo, hi) =>
+ TypeBounds(unreify(lo), unreify(hi))
+ case reflect.MethodType(formals, restpe) =>
+ MethodType(formals.map(unreify), unreify(restpe))
+ case reflect.PolyType(typeParams, typeBounds, resultType) =>
+ PolyType(typeParams.map(unreify), unreify(resultType))
+ case _ => NoType
+ }
+
+
+ /** This is woefully incomplete. It is barely enough
+ * to process the types of Constant's .
+ */
+ def unreify(symbol: reflect.Symbol): Symbol =
+ symbol match {
+ case reflect.Class(fullname) =>
+ fullname match {
+ case "scala.Unit" => definitions.UnitClass
+ case "scala.Boolean" => definitions.BooleanClass
+ case "scala.Byte" => definitions.ByteClass
+ case "scala.Short" => definitions.ShortClass
+ case "scala.Int" => definitions.IntClass
+ case "scala.Long" => definitions.LongClass
+ case "scala.Float" => definitions.FloatClass
+ case "scala.Double" => definitions.DoubleClass
+
+ case "scala.Array" => definitions.ArrayClass
+
+ case _ => NoSymbol
+
+ }
+
+ case _ => NoSymbol
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 236d46a272..10b390f041 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -645,7 +645,7 @@ trait Namers requires Analyzer {
case defn: MemberDef =>
val ainfos = for {
annot <- defn.mods.annotations
- val ainfo = typer.typedAnnotation(annot, typer.getConstant)
+ val ainfo = typer.typedAnnotation(annot)
if !ainfo.atp.isError
} yield ainfo
if (!ainfos.isEmpty) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index b1e81f6ad4..411662c96e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -110,11 +110,6 @@ trait Typers requires Analyzer {
*/
val LHSmode = 0x400
- /** The mode <code>CONSTmode</code> is set when expressions should evaluate
- * to constant sused for attribute arguments.
- */
- val CONSTmode = 0x800
-
/** The mode <code>REGPATmode</code> is set when regular expression patterns
* are allowed.
*/
@@ -129,7 +124,7 @@ trait Typers requires Analyzer {
*/
val HKmode = 0x4000 // @M: could also use POLYmode | TAPPmode
- private val stickyModes: int = EXPRmode | PATTERNmode | TYPEmode | CONSTmode | ALTmode
+ private val stickyModes: int = EXPRmode | PATTERNmode | TYPEmode | ALTmode
private def funMode(mode: int) = mode & (stickyModes | SCCmode) | FUNmode | POLYmode
@@ -1536,21 +1531,7 @@ trait Typers requires Analyzer {
if (fun.symbol == List_apply && args.isEmpty) {
atPos(tree.pos) { gen.mkNil setType restpe }
- } else if ((mode & CONSTmode) != 0 &&
- fun.symbol.owner == definitions.ArrayModule.tpe.symbol &&
- fun.symbol.name == nme.apply) {
- val elems = new Array[Constant](args2.length)
- var i = 0;
- for (val arg <- args2) arg match {
- case Literal(value) =>
- elems(i) = value
- i = i + 1
- case _ => errorTree(arg, "constant required")
- }
- val arrayConst = new ArrayConstant(elems, restpe)
- Literal(arrayConst) setType mkConstantType(arrayConst)
- }
- else
+ } else
constfold(copy.Apply(tree, fun, args2).setType(ifPatternSkipFormals(restpe)))
} else {
assert((mode & PATTERNmode) == 0); // this case cannot arise for patterns
@@ -1645,26 +1626,37 @@ trait Typers requires Analyzer {
}
}
- def getConstant(tree: Tree): Constant = tree match {
- case Literal(value) => value
- case arg => error(arg.pos, "attribute argument needs to be a constant; found: "+arg); Constant(null)
- }
-
- def typedAnnotation[T](annot: Annotation, reify: Tree => T): AnnotationInfo[T] = {
+ def typedAnnotation(annot: Annotation): AnnotationInfo = {
var attrError: Boolean = false;
def error(pos: Position, msg: String): Null = {
context.error(pos, msg)
attrError = true
null
}
- typed(annot.constr, EXPRmode | CONSTmode, AnnotationClass.tpe) match {
+ def needConst(tr: Tree) {
+ error(tr.pos, "attribute argument needs to be a constant; found: "+tr)
+ }
+
+ typed(annot.constr, EXPRmode, AnnotationClass.tpe) match {
case t @ Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
if (t.isErroneous) {
- AnnotationInfo[T](ErrorType, List(), List())
+ AnnotationInfo(ErrorType, List(), List())
}
else {
val annType = tpt.tpe
- val constrArgs = args map reify
+
+ val needsConstant =
+ (!settings.Xplugtypes.value ||
+ annType <:< ClassfileAnnotationClass.tpe)
+
+ def annotArg(tree: Tree): AnnotationArgument = {
+ val arg = new AnnotationArgument(liftcode.reify(tree))
+ if(needsConstant && !arg.isConstant)
+ needConst(tree)
+ arg
+ }
+ val constrArgs = args map annotArg
+
val attrScope = annType.decls
.filter(sym => sym.isMethod && !sym.isConstructor && sym.hasFlag(JAVA))
val names = new collection.mutable.HashSet[Symbol]
@@ -1681,7 +1673,10 @@ trait Typers requires Analyzer {
error(ntree.pos, "duplicate value for element " + name)
} else {
names -= sym
- (sym.name, reify(typed(rhs, EXPRmode | CONSTmode, sym.tpe.resultType)))
+ val annArg =
+ annotArg(
+ typed(rhs, EXPRmode, sym.tpe.resultType))
+ (sym.name, annArg)
}
}
}
@@ -1716,14 +1711,16 @@ trait Typers requires Analyzer {
case _ => NoType
}
- def typedAnnotated(annot: Annotation, arg1: Tree) = {
- def annotTypeTree(ainfo: AnnotationInfo[Any]): Tree =
+ def typedAnnotated(annot: Annotation, arg1: Tree): Tree = {
+ def annotTypeTree(ainfo: AnnotationInfo): Tree =
TypeTree(arg1.tpe.withAttribute(ainfo)) setOriginal tree
+
if (arg1.isType) {
- val annotInfo = typedAnnotation(annot, liftcode.reify)
+ val annotInfo = typedAnnotation(annot)
if (settings.Xplugtypes.value) annotTypeTree(annotInfo) else arg1
} else {
- val annotInfo = typedAnnotation(annot, getConstant)
+ val annotInfo = typedAnnotation(annot)
+
arg1 match {
case _: DefTree =>
if (!annotInfo.atp.isError) {