diff options
author | Lukas Rytz <lukas.rytz@epfl.ch> | 2009-05-30 18:10:21 +0000 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@epfl.ch> | 2009-05-30 18:10:21 +0000 |
commit | c6cf4fc02204d20f792bd493641d8ccd12421800 (patch) | |
tree | a8827ab270cf77a1c5f36a48a8cf125e1bcfb8c3 /src/compiler | |
parent | ab9381b4539097205d19df235f8cc3a5b2349e95 (diff) | |
download | scala-c6cf4fc02204d20f792bd493641d8ccd12421800.tar.gz scala-c6cf4fc02204d20f792bd493641d8ccd12421800.tar.bz2 scala-c6cf4fc02204d20f792bd493641d8ccd12421800.zip |
big overhaul of annotations implementation.
Diffstat (limited to 'src/compiler')
42 files changed, 1927 insertions, 1716 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala index c409545527..bf7a890524 100644 --- a/src/compiler/scala/tools/nsc/ast/NodePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/NodePrinters.scala @@ -41,13 +41,13 @@ abstract class NodePrinters { if (comma) buf.append(",") buf.append(EOL) } - def annotationInfoToString(attr: AnnotationInfo): String = { + def annotationInfoToString(annot: AnnotationInfo): String = { val str = new StringBuilder - str.append(attr.atp.toString()) - if (!attr.args.isEmpty) - str.append(attr.args.mkString("(", ",", ")")) - if (!attr.assocs.isEmpty) - for (((name, value), index) <- attr.assocs.zipWithIndex) { + str.append(annot.atp.toString()) + if (!annot.args.isEmpty) + str.append(annot.args.mkString("(", ",", ")")) + if (!annot.assocs.isEmpty) + for (((name, value), index) <- annot.assocs.zipWithIndex) { if (index > 0) str.append(", ") str.append(name).append(" = ").append(value) @@ -116,13 +116,13 @@ abstract class NodePrinters { if (sym hasFlag TRANS_FLAG ) buf.append(" | TRANS_FLAG") if (sym hasFlag LOCKED ) buf.append(" | LOCKED") - val attrs = ", attrs=" + ( - if (!sym.attributes.isEmpty) - sym.attributes.map(annotationInfoToString).mkString("[", ",", "]") + val annots = ", annots=" + ( + if (!sym.annotations.isEmpty) + sym.annotations.map(annotationInfoToString).mkString("[", ",", "]") else tree.asInstanceOf[MemberDef].mods.annotations) (if (buf.length() > 2) buf.substring(3) - else "0") + ", // flags=" + flagsToString(sym.flags) + attrs + else "0") + ", // flags=" + flagsToString(sym.flags) + annots } def nodeinfo(tree: Tree): String = if (infolevel == InfoLevel.Quiet) "" diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala index e00db368fe..3995bc9dbd 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala @@ -356,9 +356,6 @@ abstract class TreeBrowsers { case Annotated(annot, arg) => ("Annotated", EMPTY) - case Annotation(constr, elements) => - ("Annotation", EMPTY) - case SingletonTypeTree(ref) => ("SingletonType", EMPTY) @@ -507,10 +504,7 @@ abstract class TreeBrowsers { Nil case Annotated(annot, arg) => - annot.constr :: annot.elements ::: List(arg) - - case Annotation(constr, elements) => - constr :: elements + annot :: List(arg) case SingletonTypeTree(ref) => List(ref) @@ -668,10 +662,10 @@ abstract class TreeBrowsers { toDocument(result) :: ")") ) - case AnnotatedType(attribs, tp, _) => + case AnnotatedType(annots, tp, _) => Document.group( Document.nest(4, "AnnotatedType(" :/: - attribs.mkString("[", ",", "]") :/: + annots.mkString("[", ",", "]") :/: "," :/: toDocument(tp) :: ")") ) diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala index 2189b449ab..14573b39d7 100644 --- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala @@ -115,7 +115,7 @@ abstract class TreePrinters { } def printAnnotations(tree: Tree) { - val annots = tree.symbol.attributes + val annots = tree.symbol.annotations if (!annots.isEmpty) { annots foreach { annot => print("@"+annot+" ") } println @@ -210,14 +210,6 @@ abstract class TreePrinters { case DocDef(comment, definition) => print(comment); println; print(definition) - case Annotation(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), elements) => - print(tpt) - if (!args.isEmpty) - printRow(args, "(", ",", ")") - if (!elements.isEmpty) - print((for (Assign(name, value) <- elements) yield "val " + name + " = " + value). - mkString("{", ",", "}")) - case Template(parents, self, body) => val currentOwner1 = currentOwner if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner @@ -346,16 +338,13 @@ abstract class TreePrinters { print(tree.tpe.toString()) } - case Annotated(Annotation(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), elements), tree) => + case Annotated(Apply(Select(New(tpt), nme.CONSTRUCTOR), args), tree) => def printAnnot() { print("@"); print(tpt) if (!args.isEmpty) printRow(args, "(", ",", ")") - if (!elements.isEmpty) - print((for (Assign(name, value) <- elements) yield "val " + name + " = " + value). - mkString("{", ",", "}")) } - if (tree.isType) { printAnnot(); print(" "); print(tree) } + if (tree.isType) { print(tree); print(" "); printAnnot() } else { print(tree); print(": "); printAnnot() } case SingletonTypeTree(ref) => diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index eeb910478c..53644c6bee 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -45,12 +45,13 @@ trait Trees { // modifiers -------------------------------------------------------- - /** @param privateWithin the qualifier for a private (a type name) - * or nme.EMPTY.toTypeName, if none is given. - * @param annotations the annotations for the definition - * (i.e things starting with @) + /** @param privateWithin the qualifier for a private (a type name) + * or nme.EMPTY.toTypeName, if none is given. + * @param annotations the annotations for the definition. + * <strong>Note:</strong> the typechecker drops these annotations, + * use the AnnotationInfo's (Symbol.annotations) in later phases. */ - case class Modifiers(flags: Long, privateWithin: Name, annotations: List[Annotation]) { + case class Modifiers(flags: Long, privateWithin: Name, annotations: List[Tree]) { def isCovariant = hasFlag(COVARIANT ) // marked with `+' def isContravariant = hasFlag(CONTRAVARIANT) // marked with `-' def isPrivate = hasFlag(PRIVATE ) @@ -83,7 +84,7 @@ trait Trees { if (flags1 == flags) this else Modifiers(flags1, privateWithin, annotations) } - def withAnnotations(annots: List[Annotation]) = + def withAnnotations(annots: List[Tree]) = if (annots.isEmpty) this else Modifiers(flags, privateWithin, annotations ::: annots) } @@ -514,10 +515,6 @@ trait Trees { // The symbol of an Import is an import symbol @see Symbol.newImport // It's used primarily as a marker to check that the import has been typechecked. - /** Annotation application (constructor arguments + name-value pairs) */ - case class Annotation(constr: Tree, elements: List[Tree]) - extends TermTree - /** Documented definition, eliminated by analyzer */ case class DocDef(comment: String, definition: Tree) extends Tree { @@ -828,8 +825,12 @@ trait Trees { def TypeTree(tp: Type): TypeTree = TypeTree() setType tp // def TypeTree(tp: Type, tree : Tree): TypeTree = TypeTree(tree) setType tp - /** A tree that has an attribute attached to it */ - case class Annotated(annot: Annotation, arg: Tree) extends Tree { + /** A tree that has an annotation attached to it. Only used for annotated types and + * annotation ascriptions, annotations on definitions are stored in the Modifiers. + * Eliminated by typechecker (typedAnnotated), the annotations are then stored in + * an AnnotatedType. + */ + case class Annotated(annot: Tree, arg: Tree) extends Tree { override def isType = arg.isType override def isTerm = arg.isTerm } @@ -896,9 +897,6 @@ trait Trees { // for instance // import qual.{x, y => z, _} would be represented as // Import(qual, List(("x", "x"), ("y", "z"), (WILDCARD, null))) - case Annotation(constr, elements) => - // @constr(elements) where constr = tp(args), (an instance of Apply) - // elements = { val x1 = c1, ..., val xn = cn } case DocDef(comment, definition) => (eliminated by typecheck) // /** comment */ definition case Template(parents, self, body) => @@ -990,7 +988,6 @@ trait Trees { def TypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree): TypeDef def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree): LabelDef def Import(tree: Tree, expr: Tree, selectors: List[(Name, Name)]): Import - def Annotation(tree: Tree, constr: Tree, elements: List[Tree]): Annotation def DocDef(tree: Tree, comment: String, definition: Tree): DocDef def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]): Template def Block(tree: Tree, stats: List[Tree], expr: Tree): Block @@ -1019,7 +1016,7 @@ trait Trees { def Ident(tree: Tree, name: Name): Ident def Literal(tree: Tree, value: Constant): Literal def TypeTree(tree: Tree): TypeTree - def Annotated(tree: Tree, annot: Annotation, arg: Tree): Annotated + def Annotated(tree: Tree, annot: Tree, arg: Tree): Annotated def SingletonTypeTree(tree: Tree, ref: Tree): SingletonTypeTree def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name): SelectFromTypeTree def CompoundTypeTree(tree: Tree, templ: Template): CompoundTypeTree @@ -1045,8 +1042,6 @@ trait Trees { new LabelDef(name, params, rhs).copyAttrs(tree) def Import(tree: Tree, expr: Tree, selectors: List[(Name, Name)]) = new Import(expr, selectors).copyAttrs(tree) - def Annotation(tree: Tree, constr: Tree, elements: List[Tree]) = - new Annotation(constr, elements).copyAttrs(tree) def DocDef(tree: Tree, comment: String, definition: Tree) = new DocDef(comment, definition).copyAttrs(tree) def Template(tree: Tree, parents: List[Tree], self: ValDef, body: List[Tree]) = @@ -1103,7 +1098,7 @@ trait Trees { new Literal(value).copyAttrs(tree) def TypeTree(tree: Tree) = new TypeTree().copyAttrs(tree) - def Annotated(tree: Tree, annot: Annotation, arg: Tree) = + def Annotated(tree: Tree, annot: Tree, arg: Tree) = new Annotated(annot, arg).copyAttrs(tree) def SingletonTypeTree(tree: Tree, ref: Tree) = new SingletonTypeTree(ref).copyAttrs(tree) @@ -1123,7 +1118,7 @@ trait Trees { def this() = this(new StrictTreeCopier) def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[TypeDef], impl: Template) = tree match { case t @ ClassDef(mods0, name0, tparams0, impl0) - if (mods0 == mods && (name0 == name) && (tparams0 == tparams) && (impl0 == impl)) => t + if (mods0 == mods) && (name0 == name) && (tparams0 == tparams) && (impl0 == impl) => t case _ => treeCopy.ClassDef(tree, mods, name, tparams, impl) } def PackageDef(tree: Tree, name: Name, stats: List[Tree]) = tree match { @@ -1162,11 +1157,6 @@ trait Trees { if (expr0 == expr) && (selectors0 == selectors) => t case _ => treeCopy.Import(tree, expr, selectors) } - def Annotation(tree: Tree, constr: Tree, elements: List[Tree]) = tree match { - case t @ Annotation(constr0, elements0) - if (constr0 == constr) && (elements0 == elements) => t - case _ => treeCopy.Annotation(tree, constr, elements) - } def DocDef(tree: Tree, comment: String, definition: Tree) = tree match { case t @ DocDef(comment0, definition0) if (comment0 == comment) && (definition0 == definition) => t @@ -1306,7 +1296,7 @@ trait Trees { case t @ TypeTree() => t case _ => treeCopy.TypeTree(tree) } - def Annotated(tree: Tree, annot: Annotation, arg: Tree) = tree match { + def Annotated(tree: Tree, annot: Tree, arg: Tree) = tree match { case t @ Annotated(annot0, arg0) if (annot0==annot) => t case _ => treeCopy.Annotated(tree, annot, arg) @@ -1358,31 +1348,34 @@ trait Trees { } case ClassDef(mods, name, tparams, impl) => atOwner(tree.symbol) { - treeCopy.ClassDef(tree, mods, name, transformTypeDefs(tparams), transformTemplate(impl)) + treeCopy.ClassDef(tree, transformModifiers(mods), name, + transformTypeDefs(tparams), transformTemplate(impl)) } case ModuleDef(mods, name, impl) => atOwner(tree.symbol.moduleClass) { - treeCopy.ModuleDef(tree, mods, name, transformTemplate(impl)) + treeCopy.ModuleDef(tree, transformModifiers(mods), + name, transformTemplate(impl)) } case ValDef(mods, name, tpt, rhs) => atOwner(tree.symbol) { - treeCopy.ValDef(tree, mods, name, transform(tpt), transform(rhs)) + treeCopy.ValDef(tree, transformModifiers(mods), + name, transform(tpt), transform(rhs)) } case DefDef(mods, name, tparams, vparamss, tpt, rhs) => atOwner(tree.symbol) { - treeCopy.DefDef( - tree, mods, name, transformTypeDefs(tparams), transformValDefss(vparamss), transform(tpt), transform(rhs)) + treeCopy.DefDef(tree, transformModifiers(mods), name, + transformTypeDefs(tparams), transformValDefss(vparamss), + transform(tpt), transform(rhs)) } case TypeDef(mods, name, tparams, rhs) => atOwner(tree.symbol) { - treeCopy.TypeDef(tree, mods, name, transformTypeDefs(tparams), transform(rhs)) + treeCopy.TypeDef(tree, transformModifiers(mods), name, + transformTypeDefs(tparams), transform(rhs)) } case LabelDef(name, params, rhs) => treeCopy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LamdaLifter.proxy' case Import(expr, selectors) => treeCopy.Import(tree, transform(expr), selectors) - case Annotation(constr, elements) => - treeCopy.Annotation(tree, transform(constr), transformTrees(elements)) case DocDef(comment, definition) => treeCopy.DocDef(tree, comment, transform(definition)) case Template(parents, self, body) => @@ -1442,7 +1435,7 @@ trait Trees { case TypeTree() => treeCopy.TypeTree(tree) case Annotated(annot, arg) => - treeCopy.Annotated(tree, transform(annot).asInstanceOf[Annotation], transform(arg)) + treeCopy.Annotated(tree, transform(annot), transform(arg)) case SingletonTypeTree(ref) => treeCopy.SingletonTypeTree(tree, transform(ref)) case SelectFromTypeTree(qualifier, selector) => @@ -1482,6 +1475,8 @@ trait Trees { if (exprOwner != currentOwner && stat.isTerm) atOwner(exprOwner)(transform(stat)) else transform(stat)) filter (EmptyTree !=) def transformUnit(unit: CompilationUnit) { unit.body = transform(unit.body) } + def transformModifiers(mods: Modifiers): Modifiers = + Modifiers(mods.flags, mods.privateWithin, transformTrees(mods.annotations)) def atOwner[A](owner: Symbol)(trans: => A): A = { val prevOwner = currentOwner @@ -1525,8 +1520,6 @@ trait Trees { traverseTrees(params); traverse(rhs) case Import(expr, selectors) => traverse(expr) - case Annotation(constr, elements) => - traverse(constr); traverseTrees(elements) case Annotated(annot, arg) => traverse(annot); traverse(arg) case DocDef(comment, definition) => diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 2c12facda4..229c7aeb5a 100755 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -769,7 +769,7 @@ self => } def annotTypeRest(t: Tree): Tree = - (t /: annotations(false)) (makeAnnotated) + (t /: annotations(false, false)) (makeAnnotated) /** SimpleType ::= SimpleType TypeArgs * | SimpleType `#' Id @@ -1021,7 +1021,7 @@ self => syntaxErrorOrIncomplete("`*' expected", true) } } else if (in.token == AT) { - t = (t /: annotations(false)) (makeAnnotated) + t = (t /: annotations(false, false)) (makeAnnotated) } else { t = atPos(t.pos.start, colonPos) { val tpt = @@ -1575,50 +1575,29 @@ self => loop(NoMods) } - /** Annotations ::= {Annotation [nl]} - * Annotation ::= `@' AnnotationExpr + /** Annotations ::= {`@' SimpleType {ArgumentExprs}} + * ConsrAnnotations ::= {`@' SimpleType ArgumentExprs} */ - def annotations(skipNewLines: Boolean): List[Annotation] = { - var annots = new ListBuffer[Annotation] + def annotations(skipNewLines: Boolean, requireOneArgList: Boolean): List[Tree] = { + var annots = new ListBuffer[Tree] while (in.token == AT) { in.nextToken() - annots += annotationExpr() + annots += annotationExpr(requireOneArgList) if (skipNewLines) newLineOpt() } annots.toList } - /** AnnotationExpr ::= StableId [TypeArgs] [`(' [Exprs] `)'] [[nl] `{' {NameValuePair} `}'] - * NameValuePair ::= val id `=' PrefixExpr - */ - def annotationExpr(): Annotation = { - def nameValuePair(): Tree = { - atPos(in.offset) { - accept(VAL) - val aname = ident() - accept(EQUALS) - val rhs = stripParens(prefixExpr()) - ValDef(NoMods, aname, TypeTree(), rhs) - } - } + def annotationExpr(requireOneArgList: Boolean): Tree = { atPos(in.offset) { - var t: Tree = convertToTypeId(stableId()) - if (in.token == LBRACKET) - t = AppliedTypeTree(t, typeArgs(false, false)) - val args = if (in.token == LPAREN) argumentExprs() else List() - newLineOptWhenFollowedBy(LBRACE) - val nameValuePairs: List[Tree] = if (in.token == LBRACE) { - in.nextToken() - val nvps = new ListBuffer[Tree] += nameValuePair() - while (in.token == COMMA) { - in.nextToken() - nvps += nameValuePair() - } - accept(RBRACE) - nvps.toList - } else List() - val constr = New(t, List(args)) - Annotation(constr, nameValuePairs) + val t = simpleType(false) + val argss = new ListBuffer[List[Tree]] + if (requireOneArgList) + argss += argumentExprs() + else if (in.token == LPAREN) + do { argss += argumentExprs() } while (in.token == LPAREN) + else argss += List() + New(t, argss.toList) } } @@ -1638,7 +1617,7 @@ self => var caseParam = ofCaseClass def param(): ValDef = { val start = in.offset - val annots = annotations(false) + val annots = annotations(false, false) var mods = Modifiers(Flags.PARAM) if (owner.isTypeName) { mods = modifiers() | Flags.PARAMACCESSOR @@ -1926,12 +1905,12 @@ self => } /** IDE hook: for non-local defs or dcls with modifiers and annotations */ def nonLocalDefOrDcl : List[Tree] = { - val annots = annotations(true) + val annots = annotations(true, false) defOrDcl(modifiers() withAnnotations annots) } /** not hooked by the IDE, will not undergo stubbing. Used for early initialization blocks. */ def preNonLocalDefOrDcl : List[Tree] = { - val annots = annotations(true) + val annots = annotations(true, false) defOrDcl(modifiers() withAnnotations annots) } @@ -2111,7 +2090,7 @@ self => /** Hook for IDE, for top-level classes/objects */ def topLevelTmplDef: Tree = { - val annots = annotations(true) + val annots = annotations(true, false) val mods = modifiers() withAnnotations annots tmplDef(mods) } @@ -2156,7 +2135,7 @@ self => syntaxError("traits cannot have type parameters with <% bounds", false) implicitClassViews = List() } - val constrAnnots = annotations(false) + val constrAnnots = annotations(false, true) val (constrMods, vparamss) = if (mods.hasFlag(Flags.TRAIT)) (Modifiers(Flags.TRAIT), List()) else (accessModifierOpt(), paramClauses(name, implicitClassViews, mods.hasFlag(Flags.CASE))) @@ -2457,7 +2436,7 @@ self => */ def localDef : List[Tree] = { - val annots = annotations(true) + val annots = annotations(true, false) val mods = localModifiers() withAnnotations annots if (!(mods hasFlag ~(Flags.IMPLICIT | Flags.LAZY))) defOrDcl(mods) else List(tmplDef(mods)) diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 728dd99d27..687e5f8e21 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -109,7 +109,7 @@ abstract class TreeBuilder { case _ => t } - def makeAnnotated(t: Tree, annot: Annotation): Tree = atPos(annot.pos union t.pos)(Annotated(annot, t)) + def makeAnnotated(t: Tree, annot: Tree): Tree = atPos(annot.pos union t.pos)(Annotated(annot, t)) def makeSelfDef(name: Name, tpt: Tree): ValDef = ValDef(Modifiers(PRIVATE), name, tpt, EmptyTree) @@ -374,7 +374,7 @@ abstract class TreeBuilder { makeVisitor(cases, checkExhaustive, "x$") private def makeUnchecked(expr: Tree): Tree = - Annotated(Annotation(New(scalaDot(definitions.UncheckedClass.name), List(List())), List()), expr) + Annotated(New(scalaDot(definitions.UncheckedClass.name), List(List())), expr) /** Create visitor <x => x match cases> */ def makeVisitor(cases: List[CaseDef], checkExhaustive: Boolean, prefix: String): Tree = { diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 53b3317853..822c3ba4d9 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -108,7 +108,7 @@ abstract class GenICode extends SubComponent { var ctx1 = ctx.enterMethod(m, tree.asInstanceOf[DefDef]) addMethodParams(ctx1, vparamss) - m.native = m.symbol.hasAttribute(definitions.NativeAttr) + m.native = m.symbol.hasAnnotation(definitions.NativeAttr) if (!m.isDeferred && !m.native) { ctx1 = genLoad(rhs, ctx1, m.returnType); diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index bcadd07137..9cfdf24ffc 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -157,7 +157,7 @@ abstract class GenJVM extends SubComponent { if (parents.isEmpty) parents = definitions.ObjectClass.tpe :: parents; - for (attr <- c.symbol.attributes) attr match { + for (annot <- c.symbol.annotations) annot match { case AnnotationInfo(tp, _, _) if tp.typeSymbol == SerializableAttr => parents = parents ::: List(definitions.SerializableClass.tpe) case AnnotationInfo(tp, _, _) if tp.typeSymbol == CloneableAttr => @@ -220,10 +220,10 @@ abstract class GenJVM extends SubComponent { clasz.methods foreach genMethod addGenericSignature(jclass, c.symbol, c.symbol.owner) - addAnnotations(jclass, c.symbol.attributes) + addAnnotations(jclass, c.symbol.annotations) emitClass(jclass, c.symbol) - if (c.symbol hasAttribute BeanInfoAttr) + if (c.symbol hasAnnotation BeanInfoAttr) genBeanInfoClass(c) } @@ -234,7 +234,7 @@ abstract class GenJVM extends SubComponent { * @author Ross Judson (ross.judson@soletta.com) */ def genBeanInfoClass(c: IClass) { - val description = c.symbol.attributes.find(_.atp.typeSymbol == BeanDescriptionAttr) + val description = c.symbol.annotations.find(_.atp.typeSymbol == BeanDescriptionAttr) // informProgress(description.toString()) val beanInfoClass = fjbgContext.JClass(javaFlags(c.symbol), @@ -328,85 +328,90 @@ abstract class GenJVM extends SubComponent { addAttribute(jmethod, nme.ExceptionsATTR, buf) } - /** Whether an annotation should be emitted as a Java annotation */ - private def shouldEmitAttribute(annot: AnnotationInfo) = - (annot.atp.typeSymbol.hasFlag(Flags.JAVA) && + /** Whether an annotation should be emitted as a Java annotation + * .initialize: if 'annnot' is read from pickle, atp might be un-initialized + */ + private def shouldEmitAnnotation(annot: AnnotationInfo) = + (annot.atp.typeSymbol.initialize.hasFlag(Flags.JAVA) && annot.atp.typeSymbol.isNonBottomSubClass(definitions.ClassfileAnnotationClass) && - annot.isConstant) - - - private def emitAttributes(cpool: JConstantPool, buf: ByteBuffer, attributes: List[AnnotationInfo]): Int = { -// val cpool = jclass.getConstantPool() - - def emitElement(const: Constant): Unit = const.tag match { - case BooleanTag => - buf.put('Z'.toByte) - buf.putShort(cpool.addInteger(if(const.booleanValue) 1 else 0).toShort) - case ByteTag => - buf.put('B'.toByte) - buf.putShort(cpool.addInteger(const.byteValue).toShort) - case ShortTag => - buf.put('S'.toByte) - buf.putShort(cpool.addInteger(const.shortValue).toShort) - case CharTag => - buf.put('C'.toByte) - buf.putShort(cpool.addInteger(const.charValue).toShort) - case IntTag => - buf.put('I'.toByte) - buf.putShort(cpool.addInteger(const.intValue).toShort) - case LongTag => - buf.put('J'.toByte) - buf.putShort(cpool.addLong(const.longValue).toShort) - case FloatTag => - buf.put('F'.toByte) - buf.putShort(cpool.addFloat(const.floatValue).toShort) - case DoubleTag => - buf.put('D'.toByte) - buf.putShort(cpool.addDouble(const.doubleValue).toShort) - case StringTag => - buf.put('s'.toByte) - buf.putShort(cpool.addUtf8(const.stringValue).toShort) - case ClassTag => - buf.put('c'.toByte) - buf.putShort(cpool.addUtf8(javaType(const.typeValue).getSignature()).toShort) - case EnumTag => - buf.put('e'.toByte) - buf.putShort(cpool.addUtf8(javaType(const.tpe).getSignature()).toShort) - buf.putShort(cpool.addUtf8(const.symbolValue.name.toString).toShort) - case ArrayTag => + annot.args.isEmpty) + + private def emitJavaAnnotations(cpool: JConstantPool, buf: ByteBuffer, annotations: List[AnnotationInfo]): Int = { + def emitArgument(arg: ConstantAnnotationArgument): Unit = arg match { + case LiteralAnnotationArgument(const) => + const.tag match { + case BooleanTag => + buf.put('Z'.toByte) + buf.putShort(cpool.addInteger(if(const.booleanValue) 1 else 0).toShort) + case ByteTag => + buf.put('B'.toByte) + buf.putShort(cpool.addInteger(const.byteValue).toShort) + case ShortTag => + buf.put('S'.toByte) + buf.putShort(cpool.addInteger(const.shortValue).toShort) + case CharTag => + buf.put('C'.toByte) + buf.putShort(cpool.addInteger(const.charValue).toShort) + case IntTag => + buf.put('I'.toByte) + buf.putShort(cpool.addInteger(const.intValue).toShort) + case LongTag => + buf.put('J'.toByte) + buf.putShort(cpool.addLong(const.longValue).toShort) + case FloatTag => + buf.put('F'.toByte) + buf.putShort(cpool.addFloat(const.floatValue).toShort) + case DoubleTag => + buf.put('D'.toByte) + buf.putShort(cpool.addDouble(const.doubleValue).toShort) + case StringTag => + buf.put('s'.toByte) + buf.putShort(cpool.addUtf8(const.stringValue).toShort) + case ClassTag => + buf.put('c'.toByte) + buf.putShort(cpool.addUtf8(javaType(const.typeValue).getSignature()).toShort) + case EnumTag => + buf.put('e'.toByte) + buf.putShort(cpool.addUtf8(javaType(const.tpe).getSignature()).toShort) + buf.putShort(cpool.addUtf8(const.symbolValue.name.toString).toShort) + } + + case ArrayAnnotationArgument(args) => buf.put('['.toByte) - val arr = const.arrayValue - buf.putShort(arr.length.toShort) - for (elem <- arr) emitElement(elem) + buf.putShort(args.length.toShort) + for (val elem <- args) emitArgument(elem) + + case NestedAnnotationArgument(annInfo) => + buf.put('@'.toByte) + emitAnnotation(annInfo) } - var nattr = 0 + def emitAnnotation(annotInfo: AnnotationInfo) { + val AnnotationInfo(typ, args, assocs) = annotInfo + val jtype = javaType(typ) + buf.putShort(cpool.addUtf8(jtype.getSignature()).toShort) + assert(args.isEmpty, args.toString) + buf.putShort(assocs.length.toShort) + for ((name, value) <- assocs) { + buf.putShort(cpool.addUtf8(name.toString).toShort) + emitArgument(value) + } + } + + var nannots = 0 val pos = buf.position() // put some random value; the actual number of annotations is determined at the end buf.putShort(0xbaba.toShort) - for (attrib@AnnotationInfo(typ, consts, nvPairs) <- attributes; - if shouldEmitAttribute(attrib)) - { - nattr += 1 - val jtype = javaType(typ) - buf.putShort(cpool.addUtf8(jtype.getSignature()).toShort) - assert(consts.length <= 1, consts.toString) - buf.putShort((consts.length + nvPairs.length).toShort) - if (!consts.isEmpty) { - buf.putShort(cpool.addUtf8("value").toShort) - emitElement(consts.head.constant.get) - } - for ((name, value) <- nvPairs) { - buf.putShort(cpool.addUtf8(name.toString).toShort) - emitElement(value.constant.get) - } + for (annot <- annotations if shouldEmitAnnotation(annot)) { + nannots += 1 + emitAnnotation(annot) } // save the number of annotations - buf.putShort(pos, nattr.toShort) - nattr + buf.putShort(pos, nannots.toShort) + nannots } def addGenericSignature(jmember: JMember, sym: Symbol, owner: Symbol) { @@ -429,31 +434,28 @@ abstract class GenJVM extends SubComponent { } } - def addAnnotations(jmember: JMember, attributes: List[AnnotationInfo]) { - val toEmit = attributes.filter(shouldEmitAttribute(_)) + def addAnnotations(jmember: JMember, annotations: List[AnnotationInfo]) { + val toEmit = annotations.filter(shouldEmitAnnotation(_)) if (toEmit.isEmpty) return val buf: ByteBuffer = ByteBuffer.allocate(2048) - emitAttributes(jmember.getConstantPool, buf, toEmit) + emitJavaAnnotations(jmember.getConstantPool, buf, toEmit) addAttribute(jmember, nme.RuntimeAnnotationATTR, buf) } - def addParamAnnotations(pattrss: List[List[AnnotationInfo]]) { - val attributes = for (attrs <- pattrss) yield - for (attr @ AnnotationInfo(tpe, _, _) <- attrs; - if attr.isConstant; - if tpe.typeSymbol isNonBottomSubClass definitions.ClassfileAnnotationClass) yield attr; - if (attributes.forall(_.isEmpty)) return; + def addParamAnnotations(jmethod: JMethod, pannotss: List[List[AnnotationInfo]]) { + val annotations = pannotss map (annots => annots.filter(shouldEmitAnnotation(_))) + if (annotations.forall(_.isEmpty)) return; val buf: ByteBuffer = ByteBuffer.allocate(2048) // number of parameters - buf.put(attributes.length.toByte) - for (attrs <- attributes) - emitAttributes(jmethod.getConstantPool, buf, attrs) + buf.put(annotations.length.toByte) + for (annots <- annotations) + emitJavaAnnotations(jmethod.getConstantPool, buf, annots) addAttribute(jmethod, nme.RuntimeParamAnnotationATTR, buf) } @@ -519,7 +521,7 @@ abstract class GenJVM extends SubComponent { log("Adding field: " + f.symbol.fullNameString); var attributes = 0 - f.symbol.attributes foreach { a => a match { + f.symbol.annotations foreach { a => a match { case AnnotationInfo(tp, _, _) if tp.typeSymbol == TransientAtt => attributes = attributes | JAccessFlags.ACC_TRANSIENT case AnnotationInfo(tp, _, _) if tp.typeSymbol == VolatileAttr => @@ -535,7 +537,7 @@ abstract class GenJVM extends SubComponent { javaName(f.symbol), javaType(f.symbol.tpe)); addGenericSignature(jfield, f.symbol, clasz.symbol) - addAnnotations(jfield, f.symbol.attributes) + addAnnotations(jfield, f.symbol.annotations) } def genMethod(m: IMethod) { @@ -597,10 +599,10 @@ abstract class GenJVM extends SubComponent { } addGenericSignature(jmethod, m.symbol, clasz.symbol) - val (excs, others) = splitAnnotations(m.symbol.attributes, ThrowsAttr) + val (excs, others) = splitAnnotations(m.symbol.annotations, ThrowsAttr) addExceptionsAttribute(jmethod, excs) addAnnotations(jmethod, others) - addParamAnnotations(m.params.map(_.sym.attributes)) + addParamAnnotations(jmethod, m.params.map(_.sym.annotations)) } private def addRemoteException(jmethod: JMethod, meth: Symbol) { @@ -613,10 +615,11 @@ abstract class GenJVM extends SubComponent { case _ => false } - if (remoteClass || (meth.hasAttribute(RemoteAttr) && jmethod.isPublic())) { + if (remoteClass || + (meth.hasAnnotation(RemoteAttr) && jmethod.isPublic())) { val ainfo = AnnotationInfo(ThrowsAttr.tpe, List(new AnnotationArgument(Constant(RemoteException))), List()) - if (!meth.attributes.exists(isRemoteThrows)) { - meth.attributes = ainfo :: meth.attributes; + if (!meth.annotations.exists(isRemoteThrows)) { + meth.addAnnotation(ainfo) } } } @@ -732,9 +735,10 @@ abstract class GenJVM extends SubComponent { if (!m.hasFlag(Flags.DEFERRED)) addGenericSignature(mirrorMethod, m, module) - val (throws, others) = splitAnnotations(m.attributes, ThrowsAttr) + val (throws, others) = splitAnnotations(m.annotations, ThrowsAttr) addExceptionsAttribute(mirrorMethod, throws) addAnnotations(mirrorMethod, others) + addParamAnnotations(mirrorMethod, m.info.params.map(_.annotations)) } /** Add forwarders for all methods defined in `module' that don't conflict with @@ -1521,7 +1525,7 @@ abstract class GenJVM extends SubComponent { val attr = fjbgContext.JOtherAttribute(jclass, jmethod, - "LocalVariableTable", + nme.LocalVariableTableATTR.toString, lvTab.array()) jcode.addAttribute(attr) } diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index e9c8680b25..6b101fb10d 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -294,29 +294,30 @@ abstract class GenMSIL extends SubComponent { } } - def addAttributes(member: ICustomAttributeSetter, attributes: List[AnnotationInfo]) { - return // FIXME - + def addAttributes(member: ICustomAttributeSetter, annotations: List[AnnotationInfo]) { + return // TODO: implement at some point + } +/* if (settings.debug.value) - log("creating attributes: " + attributes + " for member : " + member) - for (attr@ AnnotationInfo(typ, annArgs, nvPairs) <- attributes ; - if attr.isConstant) - /* !typ.typeSymbol.hasFlag(Flags.JAVA) */ + log("creating annotations: " + annotations + " for member : " + member) + for (annot@ AnnotationInfo(typ, annArgs, nvPairs) <- annotations ; + if annot.isConstant) + //!typ.typeSymbol.hasFlag(Flags.JAVA) { // assert(consts.length <= 1, -// "too many constant arguments for attribute; "+consts.toString()) +// "too many constant arguments for annotations; "+consts.toString()) - // Problem / TODO having the symbol of the attribute type would be nicer + // Problem / TODO having the symbol of the annotations type would be nicer // (i hope that type.typeSymbol is the same as the one in types2create) - // AND: this will crash if the attribute Type is already compiled (-> not a typeBuilder) + // AND: this will crash if the annotations Type is already compiled (-> not a typeBuilder) // when this is solved, types2create will be the same as icodes.classes, thus superfluous - val attrType: TypeBuilder = getType(typ.typeSymbol).asInstanceOf[TypeBuilder] -// val attrType: MsilType = getType(typ.typeSymbol) + val annType: TypeBuilder = getType(typ.typeSymbol).asInstanceOf[TypeBuilder] +// val annType: MsilType = getType(typ.typeSymbol) // Problem / TODO: i have no idea which constructor is used. This // information should be available in AnnotationInfo. - attrType.CreateType() // else, GetConstructors can't be used - val constr: ConstructorInfo = attrType.GetConstructors()(0) + annType.CreateType() // else, GetConstructors can't be used + val constr: ConstructorInfo = annType.GetConstructors()(0) // prevent a second call of CreateType, only needed because there's no // otehr way than GetConstructors()(0) to get the constructor, if there's // no constructor symbol available. @@ -327,9 +328,9 @@ abstract class GenMSIL extends SubComponent { (for((n,v) <- nvPairs) yield (n, v.constant.get))) member.SetCustomAttribute(constr, args) } - } + } */ - def getAttributeArgs(consts: List[Constant], nvPairs: List[(Name, Constant)]): Array[Byte] = { +/* def getAttributeArgs(consts: List[Constant], nvPairs: List[(Name, Constant)]): Array[Byte] = { val buf = ByteBuffer.allocate(2048) // FIXME: this may be not enough! buf.order(ByteOrder.LITTLE_ENDIAN) buf.putShort(1.toShort) // signature @@ -431,7 +432,7 @@ abstract class GenMSIL extends SubComponent { val length = buf.position() buf.array().slice(0, length) - } + } */ def writeAssembly() { if (entryPoint != null) { @@ -533,7 +534,7 @@ abstract class GenMSIL extends SubComponent { assert(!isTopLevelModule(sym), "can't remove the 'if'") } - addAttributes(tBuilder, sym.attributes) + addAttributes(tBuilder, sym.annotations) if (iclass.symbol != definitions.ArrayClass) iclass.methods foreach genMethod @@ -1858,10 +1859,10 @@ abstract class GenMSIL extends SubComponent { mf = mf | (if (sym.isTrait && !sym.isImplClass) TypeAttributes.Interface else TypeAttributes.Class) mf = mf | (if (sym isFinal) TypeAttributes.Sealed else 0) - sym.attributes foreach { a => a match { + sym.annotations foreach { a => a match { case AnnotationInfo(SerializableAttr, _, _) => - // TODO: add the Serializable TypeAttribute also if the attribute - // System.SerializableAttribute is present (.net attribute, not scala) + // TODO: add the Serializable TypeAttribute also if the annotation + // System.SerializableAttribute is present (.net annotation, not scala) // Best way to do it: compare with // definitions.getClass("System.SerializableAttribute").tpe // when frontend available @@ -1906,9 +1907,9 @@ abstract class GenMSIL extends SubComponent { mf = mf | FieldAttributes.Static // TRANSIENT: "not nerialized", VOLATILE: doesn't exist on .net - // TODO: add this attribute also if the class has the custom attribute + // TODO: add this annotation also if the class has the custom attribute // System.NotSerializedAttribute - sym.attributes.foreach( a => a match { + sym.annotations.foreach( a => a match { case AnnotationInfo(TransientAtt, _, _) => mf = mf | FieldAttributes.NotSerialized case _ => () @@ -2062,7 +2063,7 @@ abstract class GenMSIL extends SubComponent { var attributes = msilFieldFlags(sym) val fBuilder = mtype.DefineField(msilName(sym), msilType(sym.tpe), attributes) fields(sym.asInstanceOf[clrTypes.global.Symbol]) = fBuilder - addAttributes(fBuilder, sym.attributes) + addAttributes(fBuilder, sym.annotations) } if (iclass.symbol != definitions.ArrayClass) @@ -2084,7 +2085,7 @@ abstract class GenMSIL extends SubComponent { constr.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym)) } mapConstructor(sym, constr) - addAttributes(constr, sym.attributes) + addAttributes(constr, sym.annotations) } else { var resType = msilType(m.returnType) val method = @@ -2094,7 +2095,7 @@ abstract class GenMSIL extends SubComponent { } if (!methods.contains(sym.asInstanceOf[clrTypes.global.Symbol])) mapMethod(sym, method) - addAttributes(method, sym.attributes) + addAttributes(method, sym.annotations) if (settings.debug.value) log("\t created MethodBuilder " + method) } @@ -2123,7 +2124,7 @@ abstract class GenMSIL extends SubComponent { } private def isCloneable(sym: Symbol): Boolean = { - !sym.attributes.forall( a => a match { + !sym.annotations.forall( a => a match { case AnnotationInfo(CloneableAttr, _, _) => false case _ => true }) diff --git a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala index 23a100ba44..c0252d84cc 100644 --- a/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala +++ b/src/compiler/scala/tools/nsc/backend/opt/Inliners.scala @@ -486,8 +486,8 @@ abstract class Inliners extends SubComponent { */ def shouldInline(caller: IMethod, callee: IMethod): Boolean = { if (caller.symbol.hasFlag(Flags.BRIDGE)) return false; - if (callee.symbol.hasAttribute(ScalaNoInlineAttr)) return false - if (callee.symbol.hasAttribute(ScalaInlineAttr)) return true + if (callee.symbol.hasAnnotation(ScalaNoInlineAttr)) return false + if (callee.symbol.hasAnnotation(ScalaInlineAttr)) return true if (settings.debug.value) log("shouldInline: " + caller + " with " + callee) var score = 0 diff --git a/src/compiler/scala/tools/nsc/doc/ModelExtractor.scala b/src/compiler/scala/tools/nsc/doc/ModelExtractor.scala index 7261043505..fd954071c7 100644 --- a/src/compiler/scala/tools/nsc/doc/ModelExtractor.scala +++ b/src/compiler/scala/tools/nsc/doc/ModelExtractor.scala @@ -84,7 +84,7 @@ trait ModelExtractor { override def toString = sym.toString def comment: Option[String] = global.comments.get(sym) // comments decoded, now what? - def attributes = sym.attributes + def attributes = sym.annotations def decodeComment: Option[Comment] = { val comment0 = this.comment if (comment0.isEmpty) None @@ -190,7 +190,7 @@ trait ModelExtractor { trait TopLevel extends ClassOrObject class TopLevelClass (sym: Symbol) extends Entity(sym) with TopLevel with Clazz class TopLevelObject(sym: Symbol) extends Entity(sym) with TopLevel with Object { - override def attributes = sym.moduleClass.attributes + override def attributes = sym.moduleClass.annotations } def compare(pathA: List[ClassOrObject], pathB: List[ClassOrObject]): Int = { @@ -337,7 +337,7 @@ trait ModelExtractor { case class NestedClass(override val sym: ClassSymbol) extends NestedClassOrObject(sym) with Clazz case class NestedObject(override val sym: ModuleSymbol) extends NestedClassOrObject(sym) with Object { - override def attributes = sym.moduleClass.attributes + override def attributes = sym.moduleClass.annotations } def isVisible(sym: Symbol): Boolean = { diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 9539cbac8c..5508585678 100755 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -330,8 +330,8 @@ trait JavaParsers extends JavaScanners { } else t } - def annotations(): List[Annotation] = { - //var annots = new ListBuffer[Annotation] + def annotations(): List[Tree] = { + //var annots = new ListBuffer[Tree] while (in.token == AT) { in.nextToken annotation() @@ -548,9 +548,7 @@ trait JavaParsers extends JavaScanners { if (parentToken == AT && in.token == DEFAULT) { val annot = atPos(pos) { - Annotation( - New(rootId(nme.AnnotationDefaultATTR.toTypeName), List(List())), - List()) + New(rootId(nme.AnnotationDefaultATTR.toTypeName), List(List())) } mods1 = Modifiers(mods1.flags, mods1.privateWithin, annot :: mods1.annotations) skipTo(SEMI) diff --git a/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala b/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala index 735943b4ad..ed54328e30 100644 --- a/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala +++ b/src/compiler/scala/tools/nsc/symtab/AnnotationCheckers.scala @@ -55,8 +55,8 @@ trait AnnotationCheckers { /** Check that the annotations on two types conform. To do * so, consult all registered annotation checkers. */ def annotationsConform(tp1: Type, tp2: Type): Boolean = { - /* Finish quickly if there are no attributes */ - if (tp1.attributes.isEmpty && tp2.attributes.isEmpty) + /* Finish quickly if there are no annotations */ + if (tp1.annotations.isEmpty && tp2.annotations.isEmpty) true else annotationCheckers.forall( diff --git a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala index dc19ea6f18..0aa228062e 100644 --- a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala +++ b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala @@ -13,63 +13,35 @@ import util._ trait AnnotationInfos { self: SymbolTable => - /** Convert a tree to a Constant, if possible */ - private def tree2cons(tree: Tree): Option[Constant] = - tree match { - case Literal(v) => Some(v) - - case Apply( - TypeApply( - meth@Select(_,_), - List(elemType)), - members) - if (definitions.ArrayModule_apply.alternatives contains meth.symbol) => - trees2consArray(members, tree.tpe) - - - case Apply(meth, members) - if (definitions.ArrayModule_apply.alternatives contains meth.symbol) => - trees2consArray(members, tree.tpe) - - case Typed(t, _) => tree2cons(t) - - case tree => - //println("could not convert: " + tree); - None - } - - private def trees2consArray(trees: Seq[Tree], arrayType:Type) - : Option[Constant] = - { - val mems = trees.map(tree2cons) - - if (mems.exists(_.isEmpty)) - None - else - Some(new ArrayConstant( - mems.map(_.get).toArray, - arrayType)) - } - - - /** An argument to an annotation. It includes a parse tree, - * and it includes a compile-time constant for the tree if possible. + /** <p>An argument to a Scala annotation. Usually created with a + * compiler tree representing the argument. If the tree can + * be converted to a compile-time Constant, the method + * <code>constant</code> returns <code>Some(c)</code>, and + * the Pickler will write the constant to the classfile, + * instead of the tree (optimisation).</p> */ - class AnnotationArgument(val intTree: Tree) { - def this(cons: Constant) = this( - Literal(cons).setType(cons.tpe)) - - - @deprecated - lazy val tree = { - object reifiers extends { - val symbols: AnnotationInfos.this.type = AnnotationInfos.this - } with Reifiers + case class AnnotationArgument(intTree: Tree) { - reifiers.reify(intTree) + /** This constructor is only used by the UnPickler, if it reads + * an AnnotationArgument that was pickled as <code>Constant</code>. + */ + def this(cons: Constant) { + this(Literal(cons).setType(cons.tpe)) } - val constant: Option[Constant] = tree2cons(intTree) + /** Contains <code>Some(c)</code> if the <code>intTree</code> can be + * converted into a compile-time Constant. Used to pickle Literals + * as Constants + */ + val constant = { + def lit2cons(t: Tree): Option[Constant] = t match { + case Literal(c) => Some(c) + // case Typed(t, _) => lit2cons(t) + // disabling this: in the expression "3: @ann", the annotation gets lost. + case _ => None + } + lit2cons(intTree) + } def isConstant = !constant.isEmpty @@ -80,25 +52,74 @@ trait AnnotationInfos { } } - /** Typed information about an annotation. It can be attached to - * either a symbol or an annotated type. + /** Subclasses of this class are used to represent Arguments + * to Java-Annotations. */ - 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 ("{", ", ", "}"))) + abstract class ConstantAnnotationArgument { + /** A tree representing that constant. Required to store java + * annotations in the pickle. + */ + def toTree: Tree = this match { + case LiteralAnnotationArgument(const) => + Literal(const) + case ArrayAnnotationArgument(args) => + Apply(Ident("array"), args.toList map (_.toTree)) + case NestedAnnotationArgument(annInfo) => + Apply(Ident("annotation"), annInfo.assocs.map(asc => Assign(Ident(asc._1), asc._2.toTree))) setType annInfo.atp + } + } + + /** Represents a compile-time Constant (Boolean, Byte, Short, + * Char, Int, Long, Float, Double, String, java.lang.Class or + * an instance of a Java enumeration value). + */ + case class LiteralAnnotationArgument(const: Constant) + extends ConstantAnnotationArgument { + override def toString = const.escapedStringValue + } + + /** Represents an array of constants */ + case class ArrayAnnotationArgument(args: Array[ConstantAnnotationArgument]) + extends ConstantAnnotationArgument { + override def toString = args.mkString("[", ", ", "]") + } + + /** Represents a constant nested Java annotation */ + case class NestedAnnotationArgument(annInfo: AnnotationInfo) + extends ConstantAnnotationArgument { + // The nested annotation should not have any Scala annotation arguments + assert(annInfo.args.isEmpty, annInfo.args) + override def toString = annInfo.toString + } + + class AnnotationInfoBase + + /** <p>Typed information about an annotation. It can be attached to + * either a symbol or an annotated type.</p> + * <p>Annotations are written to the classfile as Java annotations + * if <code>atp</code> conforms to <code>ClassfileAnnotation</code> + * (the classfile parser adds this interface to any Java annotation + * class).</p> + * <p>Annotations are pickled (written to scala symbtab attribute + * in the classfile) if <code>atp</code> inherits form + * <code>StaticAnnotation</code>.</p> + * <p>Arguments to a Scala annotation are stored in the parameter + * <code>args</code>. They are represented as compiler trees in + * general, see class AnnotationInfo. Argument to Java annotaions + * are stored as name-value pairs in <code>assocs</code>.</p> + */ + case class AnnotationInfo(atp: Type, args: List[AnnotationArgument], + assocs: List[(Name, ConstantAnnotationArgument)]) + extends AnnotationInfoBase { + + assert(args.isEmpty || assocs.isEmpty) // Java: args empty. Scala: assocs empty. + + override def toString: String = atp + + (if (!args.isEmpty) args.mkString("(", ", ", ")") else "") + + (if (!assocs.isEmpty) (assocs map { case (x, y) => x+" = "+y } mkString ("(", ", ", ")")) else "") /** Check whether all arguments and assocations are constants */ - def isConstant = - ((args forall (_.isConstant)) && - (assocs map (_._2) forall (_.isConstant))) + def isConstant = (args forall (_.isConstant)) /** Check whether the type or any of the arguments are erroneous */ def isErroneous = atp.isErroneous || args.exists(_.intTree.isErroneous) @@ -111,8 +132,11 @@ trait AnnotationInfos { def substIdentSyms(from: Symbol, to: Symbol) = { val subs = new TreeSymSubstituter(List(from), List(to)) AnnotationInfo(atp, - args.map(arg => new AnnotationArgument(subs(arg.intTree))), - assocs) + args.map(arg => new AnnotationArgument(subs(arg.intTree))), + assocs) } } + + // Definition annotations parsed in Namer (typeCompleter of definitions) have to be lazy (#1782) + case class LazyAnnotationInfo(annot: () => AnnotationInfo) extends AnnotationInfoBase } diff --git a/src/compiler/scala/tools/nsc/symtab/Constants.scala b/src/compiler/scala/tools/nsc/symtab/Constants.scala index 04e2e5181c..8b372dd8b1 100644 --- a/src/compiler/scala/tools/nsc/symtab/Constants.scala +++ b/src/compiler/scala/tools/nsc/symtab/Constants.scala @@ -29,9 +29,8 @@ trait Constants { final val StringTag = LITERALstring - LITERAL final val NullTag = LITERALnull - LITERAL final val ClassTag = LITERALclass - LITERAL + // For supporting java enumerations inside java annotations (see ClassfileParser) final val EnumTag = ClassTag + 1 - final val ArrayTag = EnumTag + 1 - final val AnnotationTag = ArrayTag + 1 def isNumeric(tag: Int) = ByteTag <= tag && tag <= DoubleTag @@ -50,7 +49,6 @@ trait Constants { else if (value.isInstanceOf[String]) StringTag else if (value.isInstanceOf[Type]) ClassTag else if (value.isInstanceOf[Symbol]) EnumTag - else if (value.isInstanceOf[Array[Constant]]) ArrayTag else if (value == null) NullTag else throw new Error("bad constant value: " + value) @@ -68,7 +66,6 @@ trait Constants { case NullTag => NullClass.tpe case ClassTag => Predef_classOfType(value.asInstanceOf[Type]) case EnumTag => symbolValue.owner.linkedClassOfClass.tpe - case AnnotationTag => AnnotationClass.tpe // what should it be? } /** We need the equals method to take account of tags as well as values. @@ -222,23 +219,7 @@ trait Constants { def symbolValue: Symbol = value.asInstanceOf[Symbol] - def arrayValue: Array[Constant] = - throw new Error("value " + value + " is not an array") - override def hashCode(): Int = if (value == null) 0 else value.hashCode() * 41 + 17 } - - class ArrayConstant(override val arrayValue: Array[Constant], - override val tpe: Type) - extends Constant(arrayValue) { - override def toString() = arrayValue.mkString("Constant(", "," , ")") - } - - /** A place-holder for annotation constants. The contents of - * the constant are not read. */ - class AnnotationConstant() - extends Constant(null) { - override val tag = AnnotationTag - } } diff --git a/src/compiler/scala/tools/nsc/symtab/IdeSupport.scala b/src/compiler/scala/tools/nsc/symtab/IdeSupport.scala index 97e883414b..a96faf35ab 100644 --- a/src/compiler/scala/tools/nsc/symtab/IdeSupport.scala +++ b/src/compiler/scala/tools/nsc/symtab/IdeSupport.scala @@ -338,7 +338,7 @@ trait IdeSupport extends SymbolTable { // added to global, not analyzers. def nuke(existing: Symbol) : Unit = { if (existing.isMonomorphicType) existing.resetFlag(Flags.MONOMORPHIC) assert(!existing.isPackage) - existing.attributes = Nil // reset attributes, we don't look at these. + existing.setAnnotations(Nil) // reset annotations, we don't look at these. if (existing.isModuleClass) { //Console.println("NUKE_N: " + existing + " " + existing.id) } else { diff --git a/src/compiler/scala/tools/nsc/symtab/Scopes.scala b/src/compiler/scala/tools/nsc/symtab/Scopes.scala index 29a01cf9c1..2793a11b20 100644 --- a/src/compiler/scala/tools/nsc/symtab/Scopes.scala +++ b/src/compiler/scala/tools/nsc/symtab/Scopes.scala @@ -346,7 +346,7 @@ trait Scopes { */ def iterator: Iterator[Symbol] = toList.iterator - @deprecated def elements = iterator + @deprecated("use `iterator'") def elements = iterator def filter(p: Symbol => Boolean): Scope = if (!(toList forall p)) newScope(toList filter p) else this diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 1dbfb99e95..b97f55f9b3 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -396,8 +396,11 @@ trait StdNames { val SignatureATTR = newTermName("Signature") val ScalaSignatureATTR = newTermName("ScalaSig") val AnnotationDefaultATTR = newTermName("AnnotationDefault") + // Stores Java annotations with RetentionPolicy.RUNTIME val RuntimeAnnotationATTR = newTermName("RuntimeVisibleAnnotations") + // Stores Java annotations with RetentionPolicy.CLASS. Currently not used (Apr 2009). val ClassfileAnnotationATTR = newTermName("RuntimeInvisibleAnnotations") + // Stores Java annotations on parameters with RetentionPolicy.RUNTIME val RuntimeParamAnnotationATTR = newTermName("RuntimeVisibleParameterAnnotations") val ScalaATTR = newTermName("Scala") } diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolWalker.scala b/src/compiler/scala/tools/nsc/symtab/SymbolWalker.scala index c5218346b6..d93b69c135 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolWalker.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolWalker.scala @@ -110,9 +110,9 @@ trait SymbolWalker { case (t : MemberDef) if t.symbol != null && t.symbol != NoSymbol => val annotated = if (sym.isModule) sym.moduleClass else sym val i = t.mods.annotations.iterator - val j = annotated.attributes.iterator + val j = annotated.annotations.iterator while (i.hasNext && j.hasNext) { - val tree = i.next.constr + val tree = i.next val ainfo = j.next val sym = ainfo.atp.typeSymbol tree.setType(ainfo.atp) @@ -150,7 +150,6 @@ trait SymbolWalker { } else tree.qualifier f(qualifier) - case tree : Annotation => f(tree.constr) case tree : Annotated => f(tree.annot); f(tree.arg) case tree : GenericApply => f(tree.fun); fs(tree.args) case tree : UnApply => f(tree.fun); fs(tree.args) diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index e0b522f400..8e72674dd7 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -92,12 +92,32 @@ trait Symbols { else -1 } - // XXX the attributes logic is essentially duplicated across Symbols and Types - var attributes: List[AnnotationInfo] = Nil - def setAttributes(attrs: List[AnnotationInfo]): this.type = { this.attributes = attrs; this } +// annotations - /** Does this symbol have an attribute of the given class? */ - def hasAttribute(cls: Symbol) = attributes exists { _.atp.typeSymbol == cls } + private var rawannots: List[AnnotationInfoBase] = Nil + + /** After the typer phase (before, look at the definition's Modifiers), contains + * the annotations attached to member a definition (class, method, type, field). + */ + def annotations: List[AnnotationInfo] = { + val annots1 = rawannots map { + case LazyAnnotationInfo(annot) => annot() + case a @ AnnotationInfo(_, _, _) => a + } filter { a => !a.atp.isError } + rawannots = annots1 + annots1 + } + + def setAnnotations(annots: List[AnnotationInfoBase]): this.type = { + this.rawannots = annots + this + } + + def addAnnotation(annot: AnnotationInfo): this.type = + setAnnotations(annot :: this.annotations) + + /** Does this symbol have an annotation of the given class? */ + def hasAnnotation(cls: Symbol) = annotations exists { _.atp.typeSymbol == cls } /** set when symbol has a modifier of the form private[X], NoSymbol otherwise. * Here's some explanation how privateWithin gets combined with access flags: @@ -389,7 +409,14 @@ trait Symbols { } } - def isDeprecated = hasAttribute(DeprecatedAttr) + def isDeprecated = hasAnnotation(DeprecatedAttr) + def deprecationMessage: Option[String] = + annotations find (_.atp.typeSymbol == DeprecatedAttr) flatMap { annot => + if (annot.args.length == 1) + annot.args.head.constant map { c => c.stringValue } + else + None + } /** Does this symbol denote a wrapper object of the interpreter or its class? */ final def isInterpreterWrapper = @@ -415,7 +442,7 @@ trait Symbols { isTerm && !hasFlag(MUTABLE) && (!hasFlag(METHOD | BYNAMEPARAM) || hasFlag(STABLE)) && - !(tpe.isVolatile && getAttributes(uncheckedStableClass).isEmpty) + !(tpe.isVolatile && !hasAnnotation(uncheckedStableClass)) def isDeferred = hasFlag(DEFERRED) && !isClass @@ -815,9 +842,6 @@ trait Symbols { */ def paramss: List[List[Symbol]] = info.paramss - def getAttributes(clazz: Symbol): List[AnnotationInfo] = - attributes.filter(_.atp.typeSymbol.isNonBottomSubClass(clazz)) - /** The least proper supertype of a class; includes all parent types * and refinement where needed. You need to compute that in a situation like this: * { @@ -944,7 +968,7 @@ trait Symbols { /** A clone of this symbol, but with given owner */ final def cloneSymbol(owner: Symbol): Symbol = cloneSymbolImpl(owner).setInfo(info.cloneInfo(this)) - .setFlag(this.rawflags).setAttributes(this.attributes) + .setFlag(this.rawflags).setAnnotations(this.annotations) /** Internal method to clone a symbol's implementation without flags or type */ diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index a21dc9b8ac..ec00d7fd96 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -30,8 +30,8 @@ import Flags._ // pre.sym[targs] case RefinedType(parents, defs) => // parent1 with ... with parentn { defs } - case AnnotatedType(attribs, tp, selfsym) => - // tp @attribs + case AnnotatedType(annots, tp, selfsym) => + // tp @annots // the following are non-value types; you cannot write them down in Scala source. @@ -195,8 +195,8 @@ trait Types { override def isComplete = underlying.isComplete override def complete(sym: Symbol) = underlying.complete(sym) override def load(sym: Symbol) { underlying.load(sym) } - override def withAttributes(attribs: List[AnnotationInfo]) = maybeRewrap(underlying.withAttributes(attribs)) - override def withoutAttributes = maybeRewrap(underlying.withoutAttributes) + override def withAnnotations(annots: List[AnnotationInfo]) = maybeRewrap(underlying.withAnnotations(annots)) + override def withoutAnnotations = maybeRewrap(underlying.withoutAnnotations) } /** The base class for all types */ @@ -778,23 +778,24 @@ trait Types { skolems } - /** Return the attributes on this type */ - val attributes: List[AnnotationInfo] = Nil - /** Test for the presence of an attribute */ - def hasAttribute(clazz: Symbol) = attributes exists { _.atp.typeSymbol == clazz } + /** Return the annotations on this type. */ + def annotations: List[AnnotationInfo] = Nil - /** Add an attribute to this type */ - def withAttribute(attrib: AnnotationInfo) = withAttributes(List(attrib)) + /** Test for the presence of an annotation */ + def hasAnnotation(clazz: Symbol) = annotations exists { _.atp.typeSymbol == clazz } - /** Add a number of attributes to this type */ - def withAttributes(attribs: List[AnnotationInfo]): Type = - attribs match { + /** Add an annotation to this type */ + def withAnnotation(annot: AnnotationInfo) = withAnnotations(List(annot)) + + /** Add a number of annotations to this type */ + def withAnnotations(annots: List[AnnotationInfo]): Type = + annots match { case Nil => this - case _ => AnnotatedType(attribs, this, NoSymbol) + case _ => AnnotatedType(annots, this, NoSymbol) } /** Remove any annotations from this type */ - def withoutAttributes = this + def withoutAnnotations = this /** Remove any annotations from this type and from any * types embedded in this type. */ @@ -1885,47 +1886,44 @@ A type's typeSymbol should never be inspected directly. override def kind = "TypeVar" } - /** A type carrying some annotations. The annotations have - * no significance to the core compiler, but can be observed - * by type-system plugins. The core compiler does take care - * to propagate annotations and to save them in the symbol - * tables of object files. - * - * @param attributes the list of annotations on the type - * @param underlying the type without the annotation - * @param selfsym a "self" symbol with type <code>underlying</code>; - * only available if -Yself-in-annots is - * turned on. Can be NoSymbol if it is not used. - */ - case class AnnotatedType(override val attributes: List[AnnotationInfo], + /** A type carrying some annotations. Created by the typechecker + * when eliminating ``Annotated'' trees (see typedAnnotated). + * + * @param annotations the list of annotations on the type + * @param underlying the type without the annotation + * @param selfsym a "self" symbol with type <code>underlying</code>; + * only available if -Yself-in-annots is turned on. Can be NoSymbol + * if it is not used. + */ + case class AnnotatedType(override val annotations: List[AnnotationInfo], override val underlying: Type, override val selfsym: Symbol) extends RewrappingTypeProxy { - assert(!attributes.isEmpty) + assert(!annotations.isEmpty) - override protected def rewrap(tp: Type) = AnnotatedType(attributes, tp, selfsym) + override protected def rewrap(tp: Type) = AnnotatedType(annotations, tp, selfsym) override def safeToString: String = { val attString = - if (attributes.isEmpty) + if (annotations.isEmpty) "" else - attributes.mkString(" @", " @", "") + annotations.mkString(" @", " @", "") underlying + attString } - /** Add a number of attributes to this type */ - override def withAttributes(attribs: List[AnnotationInfo]): Type = - AnnotatedType(attribs:::this.attributes, this, selfsym) + /** Add a number of annotations to this type */ + override def withAnnotations(annots: List[AnnotationInfo]): Type = + AnnotatedType(annots:::this.annotations, this, selfsym) - /** Remove any attributes from this type */ - override def withoutAttributes = underlying.withoutAttributes + /** Remove any annotations from this type */ + override def withoutAnnotations = underlying.withoutAnnotations /** Set the self symbol */ override def withSelfsym(sym: Symbol) = - AnnotatedType(attributes, underlying, sym) + AnnotatedType(annotations, underlying, sym) /** Drop the annotations on the bounds, unless but the low and high bounds are * exactly tp. */ @@ -1939,11 +1937,11 @@ A type's typeSymbol should never be inspected directly. // ** Replace formal type parameter symbols with actual type arguments. * / override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]) = { - val attributes1 = attributes.map(info => AnnotationInfo(info.atp.instantiateTypeParams( + val annotations1 = annotations.map(info => AnnotationInfo(info.atp.instantiateTypeParams( formals, actuals), info.args, info.assocs)) val underlying1 = underlying.instantiateTypeParams(formals, actuals) - if ((attributes1 eq attributes) && (underlying1 eq underlying)) this - else AnnotatedType(attributes1, underlying1, selfsym) + if ((annotations1 eq annotations) && (underlying1 eq underlying)) this + else AnnotatedType(annotations1, underlying1, selfsym) } /** Return the base type sequence of tp, dropping the annotations, unless the base type sequence of tp @@ -3035,7 +3033,7 @@ A type's typeSymbol should never be inspected directly. override def transform(tree: Tree): Tree = tree match { case tree@Ident(name) => - tree.tpe.withoutAttributes match { + tree.tpe.withoutAnnotations match { case DeBruijnIndex(level, pid) => if (level == 1) { if (actuals(pid).isStable) @@ -3575,9 +3573,9 @@ A type's typeSymbol should never be inspected directly. if (constr2.inst != NoType) tp1 =:= constr2.inst else isRelatable(tv2, tp1) && (tv2 tryInstantiate wildcardToTypeVarMap(tp1)) case (AnnotatedType(_,_,_), _) => - annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAttributes =:= tp2.withoutAttributes + annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations case (_, AnnotatedType(_,_,_)) => - annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAttributes =:= tp2.withoutAttributes + annotationsConform(tp1, tp2) && annotationsConform(tp2, tp1) && tp1.withoutAnnotations =:= tp2.withoutAnnotations case (_: SingletonType, _: SingletonType) => var origin1 = tp1 while (origin1.underlying.isInstanceOf[SingletonType]) { @@ -3725,9 +3723,9 @@ A type's typeSymbol should never be inspected directly. case (TypeBounds(lo1, hi1), TypeBounds(lo2, hi2)) => lo2 <:< lo1 && hi1 <:< hi2 case (AnnotatedType(_,_,_), _) => - annotationsConform(tp1, tp2) && tp1.withoutAttributes <:< tp2.withoutAttributes + annotationsConform(tp1, tp2) && tp1.withoutAnnotations <:< tp2.withoutAnnotations case (_, AnnotatedType(_,_,_)) => - annotationsConform(tp1, tp2) && tp1.withoutAttributes <:< tp2.withoutAttributes + annotationsConform(tp1, tp2) && tp1.withoutAnnotations <:< tp2.withoutAnnotations case (BoundedWildcardType(bounds), _) => bounds.lo <:< tp2 case (_, BoundedWildcardType(bounds)) => diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 9df9dc77f9..ca35798de4 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -427,18 +427,6 @@ abstract class ClassfileParser { clazz.newConstructor(NoPosition) .setFlag(clazz.flags & ConstrFlags) .setInfo(MethodType(List(), clazz.tpe))) - - // If the annotation has an attribute with name 'value' - // add a constructor for it - if (isAnnotation) { - val value = instanceDefs.lookup(nme.value) - if (value != NoSymbol) { - val constr = clazz.newConstructor(NoPosition) - instanceDefs.enter(constr - .setFlag(clazz.flags & ConstrFlags) - .setInfo(MethodType(constr.newSyntheticValueParams(List(value.tpe.resultType)), clazz.tpe))) - } - } } } else parseAttributes(clazz, classInfo) @@ -752,78 +740,87 @@ abstract class ClassfileParser { staticModule.moduleClass.sourceFile = clazz.sourceFile } } + // Attribute on methods of java annotation classes when that method has a default case nme.AnnotationDefaultATTR => - sym.attributes = - AnnotationInfo(definitions.AnnotationDefaultAttr.tpe, List(), List()) :: sym.attributes + sym.addAnnotation(AnnotationInfo(definitions.AnnotationDefaultAttr.tpe, List(), List())) in.skip(attrLen) + // Java annotatinos on classes / methods / fields with RetentionPolicy.RUNTIME case nme.RuntimeAnnotationATTR => - parseAnnotations(attrLen) - if (settings.debug.value) - global.inform("" + sym + "; attributes = " + sym.attributes) + if (!isScala) { + // no need to read annotations if isScala, ClassfileAnnotations are pickled + parseAnnotations(attrLen) + if (settings.debug.value) + global.inform("" + sym + "; annotations = " + sym.annotations) + } else + in.skip(attrLen) + + // TODO 1: parse runtime visible annotations on parameters + // case nme.RuntimeParamAnnotationATTR + + // TODO 2: also parse RuntimeInvisibleAnnotation / RuntimeInvisibleParamAnnotation, + // i.e. java annotations with RetentionPolicy.CLASS? case _ => in.skip(attrLen) } } - def parseTaggedConstant: Constant = { + + def parseAnnotationArgument: Option[ConstantAnnotationArgument] = { val tag = in.nextByte val index = in.nextChar tag match { - case STRING_TAG => Constant(pool.getName(index).toString()) - case BOOL_TAG => pool.getConstant(index) - case BYTE_TAG => pool.getConstant(index) - case CHAR_TAG => pool.getConstant(index) - case SHORT_TAG => pool.getConstant(index) - case INT_TAG => pool.getConstant(index) - case LONG_TAG => pool.getConstant(index) - case FLOAT_TAG => pool.getConstant(index) - case DOUBLE_TAG => pool.getConstant(index) - case CLASS_TAG => Constant(pool.getType(index)) + case STRING_TAG => + Some(LiteralAnnotationArgument(Constant(pool.getName(index).toString()))) + case BOOL_TAG | BYTE_TAG | CHAR_TAG | SHORT_TAG | INT_TAG | + LONG_TAG | FLOAT_TAG | DOUBLE_TAG => + Some(LiteralAnnotationArgument(pool.getConstant(index))) + case CLASS_TAG => + Some(LiteralAnnotationArgument(Constant(pool.getType(index)))) case ENUM_TAG => val t = pool.getType(index) val n = pool.getName(in.nextChar) val s = t.typeSymbol.linkedModuleOfClass.info.decls.lookup(n) assert(s != NoSymbol, t) - Constant(s) + Some(LiteralAnnotationArgument(Constant(s))) case ARRAY_TAG => - val arr = new ArrayBuffer[Constant]() - for (i <- 0 until index) { - arr += parseTaggedConstant - } - new ArrayConstant(arr.toArray, - appliedType(definitions.ArrayClass.typeConstructor, List(arr(0).tpe))) - case ANNOTATION_TAG => - parseAnnotation(index) // skip it - new AnnotationConstant() + val arr = new ArrayBuffer[ConstantAnnotationArgument]() + var hasError = false + for (i <- 0 until index) + parseAnnotationArgument match { + case Some(c) => arr += c + case None => hasError = true + } + if (hasError) None + else Some(ArrayAnnotationArgument(arr.toArray)) + case ANNOTATION_TAG => + parseAnnotation(index) map (NestedAnnotationArgument(_)) } } /** Parse and return a single annotation. If it is malformed, - * or it contains a nested annotation, return None. + * return None. */ - def parseAnnotation(attrNameIndex: Char): Option[AnnotationInfo] = - try { - val attrType = pool.getType(attrNameIndex) - val nargs = in.nextChar - val nvpairs = new ListBuffer[(Name,AnnotationArgument)] - var nestedAnnot = false // if a nested annotation is seen, - // then skip this annotation - for (i <- 0 until nargs) { - val name = pool.getName(in.nextChar) - val argConst = parseTaggedConstant - if (argConst.tag == AnnotationTag) - nestedAnnot = true - else - nvpairs += ((name, new AnnotationArgument(argConst))) + def parseAnnotation(attrNameIndex: Char): Option[AnnotationInfo] = try { + val attrType = pool.getType(attrNameIndex) + val nargs = in.nextChar + val nvpairs = new ListBuffer[(Name,ConstantAnnotationArgument)] + var hasError = false + for (i <- 0 until nargs) { + val name = pool.getName(in.nextChar) + parseAnnotationArgument match { + case Some(c) => nvpairs += ((name, c)) + case None => hasError = true } - - if (nestedAnnot) - None - else - Some(AnnotationInfo(attrType, List(), nvpairs.toList)) - } catch { - case f: FatalError => throw f // don't eat fatal errors, they mean a class was not found - case ex: Throwable => None // ignore malformed annotations ==> t1135 } + if (hasError) None + else Some(AnnotationInfo(attrType, List(), nvpairs.toList)) + } catch { + case f: FatalError => throw f // don't eat fatal errors, they mean a class was not found + case ex: Throwable => + if (settings.debug.value) + global.inform("dropping annotation on " + sym + + ", an error occured during parsing (e.g. annotation class not found)") + None // ignore malformed annotations ==> t1135 + } /** Parse a sequence of annotations and attach them to the * current symbol sym. @@ -832,12 +829,9 @@ abstract class ClassfileParser { val nAttr = in.nextChar for (n <- 0 until nAttr) parseAnnotation(in.nextChar) match { - case None => - if (settings.debug.value) - global.inform("dropping annotation on " + - sym + " that has a nested annotation") case Some(annot) => - sym.attributes = annot :: sym.attributes + sym.addAnnotation(annot) + case None => } } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/PickleBuffer.scala b/src/compiler/scala/tools/nsc/symtab/classfile/PickleBuffer.scala index c09a2c797c..608857d3e0 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/PickleBuffer.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/PickleBuffer.scala @@ -144,16 +144,20 @@ class PickleBuffer(data: Array[Byte], from: Int, to: Int) { def times[T](n: Int, op: ()=>T): List[T] = if (n == 0) List() else op() :: times(n-1, op) - /** Create an index. + /** Pickle = majorVersion_Nat minorVersion_Nat nbEntries_Nat {Entry} + * Entry = type_Nat length_Nat [actual entries] * - * @return ... + * Assumes that the ..Version_Nat are already consumed. + * + * @return an array mapping entry numbers to locations in + * the byte array where the entries start. */ def createIndex: Array[Int] = { - val index = new Array[Int](readNat()) + val index = new Array[Int](readNat()) // nbEntries_Nat for (i <- 0 until index.length) { index(i) = readIndex - readByte() - readIndex = readNat() + readIndex + readByte() // skip type_Nat + readIndex = readNat() + readIndex // read length_Nat, jump to next entry } index } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala b/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala index 799c19c53f..0e0575b4b1 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/PickleFormat.scala @@ -43,6 +43,7 @@ object PickleFormat { * | 20 METHODtpe len_Nat tpe_Ref {sym_Ref} // new method type * | 21 POLYTtpe len_Nat tpe_Ref {sym_Ref} * | 22 IMPLICITMETHODtpe len_Nat tpe_Ref {tpe_Ref} + * | 52 SUPERtpe len_Nat tpe_Ref tpe_Ref * | 24 LITERALunit len_Nat * | 25 LITERALboolean len_Nat value_Long * | 26 LITERALbyte len_Nat value_Long @@ -55,11 +56,13 @@ object PickleFormat { * | 33 LITERALstring len_Nat name_Ref * | 34 LITERALnull len_Nat * | 35 LITERALclass len_Nat type_Ref - * | 40 ATTRIBUTE len_Nat sym_Ref info_Ref {constant_Ref} {nameRef constantRef} + * | 40 SYMANNOT len_Nat sym_Ref info_Ref {AnnotArg_Ref} {name_Ref AnnotArg_Ref} // old symbolAnnot, unpickling still works @LUC TODO remove for 2.8.0 + * | 40 SYMANNOT len_Nat sym_Ref info_Ref {annotArg_Ref} {name_Ref constAnnotArg_Ref} * | 41 CHILDREN len_Nat sym_Ref {sym_Ref} - * | 42 ANNOTATEDtpe len_Nat tpe_Ref {attribtree_Ref} - * | 51 ANNOTATEDWSELFtpe len_Nat tpe_Ref sym_Ref {attribtree_Ref} - * | 43 ANNOTINFO attarg_Ref len_Nat attarg_Ref {constant_Ref attarg_Ref} + * | 42 ANNOTATEDtpe len_Nat [sym_Ref] tpe_Ref {annotinfo_Ref} + * | 43 ANNOTINFO len_Nat info_Ref numConstrArgs_Nat {annotArg_Ref} {name_Ref annotArg_Ref} // old annot info, unpickling still works @LUC TODO remove + * | 43 ANNOTINFO len_Nat info_Ref {annotArg_Ref} {name_Ref constAnnotArg_Ref} + * | 44 ANNOTARGARRAY len_Nat {constAnnotArg_Ref} * | 47 DEBRUIJNINDEXtpe len_Nat level_Nat index_Nat * | 48 EXISTENTIALtpe len_Nat type_Ref {symbol_Ref} * | 49 TREE len_Nat 1 EMPTYtree @@ -71,7 +74,7 @@ object PickleFormat { * | 49 TREE len_Nat 7 TYPEDEFtree type_Ref sym_Ref mods_Ref name_Ref tree_Ref {tree_Ref} * | 49 TREE len_Nat 8 LABELtree type_Ref sym_Ref tree_Ref {tree_Ref} * | 49 TREE len_Nat 9 IMPORTtree type_Ref sym_Ref tree_Ref {name_Ref name_Ref} - * | 49 TREE len_Nat 10 ANNOTATIONtree type_Ref sym_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 10 ANNOTATIONtree type_Ref sym_Ref tree_Ref {tree_Ref} // still unpickled @LUC TODO remove * | 49 TREE len_Nat 11 DOCDEFtree type_Ref sym_Ref string_Ref tree_Ref * | 49 TREE len_Nat 12 TEMPLATEtree type_Ref sym_Ref numparents_Nat {tree_Ref} tree_Ref {tree_Ref} * | 49 TREE len_Nat 13 BLOCKtree type_Ref tree_Ref {tree_Ref} @@ -107,7 +110,8 @@ object PickleFormat { * | 49 TREE len_Nat 43 APPLIEDTYPEtree type_Ref tree_Ref {tree_Ref} * | 49 TREE len_Nat 44 TYPEBOUNDStree type_Ref tree_Ref tree_Ref * | 49 TREE len_Nat 45 EXISTENTIALTYPEtree type_Ref tree_Ref {tree_Ref} - * | 50 MODIFIERS len_Nat flags_Long privateWithin_Ref {Annotation_Ref} + * | 50 MODIFIERS len_Nat flags_Long privateWithin_Ref {Annotation_Ref} // still unpickled, @LUC TODO: remove Annotation_Ref's + * | 50 MODIFIERS len_Nat flags_Long privateWithin_Ref * | 68 PosTYPEsym len_Nat pos_Nat SymbolInfo * | 69 PosALIASsym len_Nat pos_Nat SymbolInfo * | 70 PosCLASSsym len_Nat pos_Nat SymbolInfo [thistype_Ref] @@ -117,7 +121,8 @@ object PickleFormat { * NameInfo = <character sequence of length len_Nat in Utf8 format> * NumInfo = <len_Nat-byte signed number in big endian format> * Ref = Nat - * Attarg = Refltree | Constant + * AnnotArg = Tree | Constant + * ConstAnnotArg = Constant | AnnotInfo | AnnotArgArray * * len is remaining length after `len'. */ @@ -160,19 +165,20 @@ object PickleFormat { final val LITERALstring = 33 final val LITERALnull = 34 final val LITERALclass = 35 - final val ATTRIBUTE = 40 // an attribute with constants + final val SYMANNOT = 40 final val CHILDREN = 41 - final val ANNOTATEDtpe = 42 - final val ANNOTINFO = 43 // an annotation with trees - final val REFLTREE = 44 // prefix saying that a reflect tree is coming - // support dropped in September of 2007 + final val ANNOTINFO = 43 + final val ANNOTARGARRAY = 44 + + final val REFLTREE = 44 // @LUC TODO remove; prefix saying that a reflect tree is coming + // support dropped in September of 2007, remove for 2.8.0 - final val REFLTYPE = 45 // prefix code that means a reflect type is coming - // support dropped in September of 2007 + final val REFLTYPE = 45 // prefix code that means a reflect type is coming + // support dropped in September of 2007, remove for 2.8.0 - final val REFLSYM = 46 // prefix code that means a reflect symbol is coming - // support dropped in September of 2007 + final val REFLSYM = 46 // prefix code that means a reflect symbol is coming + // support dropped in September of 2007, remove for 2.8.0 final val DEBRUIJNINDEXtpe = 47 final val EXISTENTIALtpe = 48 @@ -187,7 +193,7 @@ object PickleFormat { final val TYPEDEFtree = 7 final val LABELtree = 8 final val IMPORTtree = 9 - final val ANNOTATIONtree = 10 + final val ANNOTATIONtree = 10 // @LUC TODO remove (still unpickling now) final val DOCDEFtree = 11 final val TEMPLATEtree = 12 final val BLOCKtree = 13 @@ -225,18 +231,19 @@ object PickleFormat { final val EXISTENTIALTYPEtree = 45 final val MODIFIERS = 50 - final val ANNOTATEDWSELFtpe = 51 // annotated type with selfsym + final val SUPERtpe = 52 final val firstSymTag = NONEsym final val lastSymTag = VALsym final val lastExtSymTag = EXTMODCLASSref - //The following two are no longer accurate, because ATTRIBUTEDtpe - //is not in the same range as the other types + //The following two are no longer accurate, because ATTRIBUTEDtpe, + //SUPERtpe, ... are not in the same range as the other types //final val firstTypeTag = NOtpe //final val lastTypeTag = POLYtpe + /** no longer emitted since September 2007, remove for 2.8.0 */ final val PosOffset = 64 final val PosTYPEsym = PosOffset + TYPEsym final val PosALIASsym = PosOffset + ALIASsym diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala index b82417c4a3..a44270468b 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala @@ -49,6 +49,7 @@ abstract class Pickler extends SubComponent { add(sym, pickle) add(sym.linkedSym, pickle) pickle.finish + // pickleHash is used to track changes in a signature (-> IDE) val doPickleHash = global.doPickleHash if (doPickleHash) { var i = 0 @@ -91,6 +92,10 @@ abstract class Pickler extends SubComponent { sym != NoSymbol && isLocal(sym.owner) || isUnrootedExistential(sym) + private def staticAnnotations(annots: List[AnnotationInfo]) = + annots filter(ann => + ann.atp.typeSymbol isNonBottomSubClass definitions.StaticAnnotationClass) + // Phase 1 methods: Populate entries/index ------------------------------------ /** Store entry <code>e</code> in index at next available position unless @@ -145,10 +150,8 @@ abstract class Pickler extends SubComponent { } putChildren(sym, children.sort((x, y) => x isLess y)) } - for (attr <- sym.attributes.reverse) { - if (attr.atp.typeSymbol isNonBottomSubClass definitions.StaticAnnotationClass) - putAnnotation(sym, attr) - } + for (annot <- staticAnnotations(sym.annotations.reverse)) + putAnnotation(sym, annot) } else if (sym != NoSymbol) { putEntry(if (sym.isModuleClass) sym.name.toTermName else sym.name) if (!sym.owner.isRoot) putSymbol(sym.owner) @@ -171,8 +174,11 @@ abstract class Pickler extends SubComponent { putSymbol(sym) case SingleType(pre, sym) => putType(pre); putSymbol(sym) + case SuperType(thistpe, supertpe) => + putType(thistpe) + putType(supertpe) case ConstantType(value) => - putConstant(value) + putConstant(value) case TypeRef(pre, sym, args) => putType(pre); putSymbol(sym); putTypes(args) case TypeBounds(lo, hi) => @@ -190,9 +196,10 @@ abstract class Pickler extends SubComponent { putType(restpe); putSymbols(tparams) case ExistentialType(tparams, restpe) => putType(restpe); putSymbols(tparams) - case AnnotatedType(attribs, tp, selfsym) => - putType(tp); putAnnotations(attribs) - if (settings.selfInAnnots.value) putSymbol(selfsym) + case AnnotatedType(annotations, underlying, selfsym) => + putType(underlying) + if (settings.selfInAnnots.value) putSymbol(selfsym) + putAnnotations(staticAnnotations(annotations)) case _ => throw new FatalError("bad type: " + tp + "(" + tp.getClass + ")") } @@ -201,199 +208,192 @@ abstract class Pickler extends SubComponent { private def putTree(tree: Tree): Unit = if (putEntry(tree)) { if (tree != EmptyTree) - putType(tree.tpe) + putType(tree.tpe) if (tree.hasSymbol) - putSymbol(tree.symbol) + putSymbol(tree.symbol) tree match { - case EmptyTree => + case EmptyTree => - case tree@PackageDef(name, stats) => - putEntry(name) + case tree@PackageDef(name, stats) => + putEntry(name) putTrees(stats) - case ClassDef(mods, name, tparams, impl) => - putMods(mods) - putEntry(name) + case ClassDef(mods, name, tparams, impl) => + putMods(mods) + putEntry(name) putTree(impl) - putTrees(tparams) - - case ModuleDef(mods, name, impl) => - putMods(mods) - putEntry(name) - putTree(impl) - - case ValDef(mods, name, tpt, rhs) => - putMods(mods) - putEntry(name) - putTree(tpt) - putTree(rhs) - - case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - putMods(mods) - putEntry(name) - putTrees(tparams) - putTreess(vparamss) - putTree(tpt) - putTree(rhs) - - - case TypeDef(mods, name, tparams, rhs) => - putMods(mods) - putEntry(name) - putTree(rhs) - putTrees(tparams) - - - case LabelDef(name, params, rhs) => - putEntry(name) - putTree(rhs) - putTrees(params) - + putTrees(tparams) - case Import(expr, selectors) => - putTree(expr) - for ((from,to) <- selectors) { - putEntry(from) - putEntry(to) - } + case ModuleDef(mods, name, impl) => + putMods(mods) + putEntry(name) + putTree(impl) - case Annotation(constr, elements) => - putTree(constr) - putTrees(elements) + case ValDef(mods, name, tpt, rhs) => + putMods(mods) + putEntry(name) + putTree(tpt) + putTree(rhs) + + case DefDef(mods, name, tparams, vparamss, tpt, rhs) => + putMods(mods) + putEntry(name) + putTrees(tparams) + putTreess(vparamss) + putTree(tpt) + putTree(rhs) + + case TypeDef(mods, name, tparams, rhs) => + putMods(mods) + putEntry(name) + putTree(rhs) + putTrees(tparams) + + case LabelDef(name, params, rhs) => + putEntry(name) + putTree(rhs) + putTrees(params) + + case Import(expr, selectors) => + putTree(expr) + for ((from,to) <- selectors) { + putEntry(from) + putEntry(to) + } - case DocDef(comment, definition) => - putConstant(Constant(comment)) - putTree(definition) + case DocDef(comment, definition) => + putConstant(Constant(comment)) + putTree(definition) - case Template(parents, self, body) => + case Template(parents, self, body) => writeNat(parents.length) - putTrees(parents) - putTree(self) - putTrees(body) + putTrees(parents) + putTree(self) + putTrees(body) - case Block(stats, expr) => - putTree(expr) - putTrees(stats) + case Block(stats, expr) => + putTree(expr) + putTrees(stats) - case CaseDef(pat, guard, body) => - putTree(pat) - putTree(guard) - putTree(body) + case CaseDef(pat, guard, body) => + putTree(pat) + putTree(guard) + putTree(body) - case Sequence(trees) => - putTrees(trees) + case Sequence(trees) => + putTrees(trees) - case Alternative(trees) => - putTrees(trees) + case Alternative(trees) => + putTrees(trees) - case Star(elem) => - putTree(elem) + case Star(elem) => + putTree(elem) - case Bind(name, body) => - putEntry(name) - putTree(body) + case Bind(name, body) => + putEntry(name) + putTree(body) - case UnApply(fun: Tree, args) => - putTree(fun) - putTrees(args) + case UnApply(fun: Tree, args) => + putTree(fun) + putTrees(args) - case ArrayValue(elemtpt, trees) => - putTree(elemtpt) - putTrees(trees) + case ArrayValue(elemtpt, trees) => + putTree(elemtpt) + putTrees(trees) - case Function(vparams, body) => - putTree(body) - putTrees(vparams) + case Function(vparams, body) => + putTree(body) + putTrees(vparams) - case Assign(lhs, rhs) => - putTree(lhs) - putTree(rhs) + case Assign(lhs, rhs) => + putTree(lhs) + putTree(rhs) - case If(cond, thenp, elsep) => - putTree(cond) - putTree(thenp) - putTree(elsep) + case If(cond, thenp, elsep) => + putTree(cond) + putTree(thenp) + putTree(elsep) - case Match(selector, cases) => - putTree(selector) - putTrees(cases) + case Match(selector, cases) => + putTree(selector) + putTrees(cases) - case Return(expr) => - putTree(expr) + case Return(expr) => + putTree(expr) - case Try(block, catches, finalizer) => - putTree(block) - putTree(finalizer) - putTrees(catches) + case Try(block, catches, finalizer) => + putTree(block) + putTree(finalizer) + putTrees(catches) - case Throw(expr) => - putTree(expr) + case Throw(expr) => + putTree(expr) - case New(tpt) => - putTree(tpt) + case New(tpt) => + putTree(tpt) - case Typed(expr, tpt) => - putTree(expr) - putTree(tpt) + case Typed(expr, tpt) => + putTree(expr) + putTree(tpt) - case TypeApply(fun, args) => - putTree(fun) - putTrees(args) + case TypeApply(fun, args) => + putTree(fun) + putTrees(args) - case Apply(fun, args) => - putTree(fun) - putTrees(args) + case Apply(fun, args) => + putTree(fun) + putTrees(args) - case ApplyDynamic(qual, args) => - writeEntry(qual) - putTrees(args) + case ApplyDynamic(qual, args) => + putTree(qual) + putTrees(args) - case Super(qual, mix) => - putEntry(qual:Name) - putEntry(mix:Name) + case Super(qual, mix) => + putEntry(qual:Name) + putEntry(mix:Name) case This(qual) => - putEntry(qual) + putEntry(qual) case Select(qualifier, selector) => - putTree(qualifier) - putEntry(selector) + putTree(qualifier) + putEntry(selector) - case Ident(name) => - putEntry(name) + case Ident(name) => + putEntry(name) - case Literal(value) => - putEntry(value) + case Literal(value) => + putEntry(value) - case TypeTree() => + case TypeTree() => - case Annotated(annot, arg) => - putTree(annot) - putTree(arg) + case Annotated(annot, arg) => + putTree(annot) + putTree(arg) - case SingletonTypeTree(ref) => - putTree(ref) + case SingletonTypeTree(ref) => + putTree(ref) - case SelectFromTypeTree(qualifier, selector) => - putTree(qualifier) - putEntry(selector) + case SelectFromTypeTree(qualifier, selector) => + putTree(qualifier) + putEntry(selector) - case CompoundTypeTree(templ: Template) => - putTree(templ) + case CompoundTypeTree(templ: Template) => + putTree(templ) - case AppliedTypeTree(tpt, args) => - putTree(tpt) - putTrees(args) + case AppliedTypeTree(tpt, args) => + putTree(tpt) + putTrees(args) - case TypeBoundsTree(lo, hi) => - putTree(lo) - putTree(hi) + case TypeBoundsTree(lo, hi) => + putTree(lo) + putTree(hi) - case ExistentialTypeTree(tpt, whereClauses) => - putTree(tpt) - putTrees(whereClauses) + case ExistentialTypeTree(tpt, whereClauses) => + putTree(tpt) + putTrees(whereClauses) } } @@ -403,63 +403,78 @@ abstract class Pickler extends SubComponent { private def putTreess(treess: List[List[Tree]]) = treess.foreach(putTrees _) + /** only used when pickling trees, i.e. in an + * argument of some Annotation */ private def putMods(mods: Modifiers) = if (putEntry(mods)) { - val Modifiers(flags, privateWithin, annotations) = mods + // annotations in Modifiers are removed by the typechecker + val Modifiers(flags, privateWithin, Nil) = mods putEntry(privateWithin) - putTrees(annotations) } /** Store a constant in map <code>index</code> along with * anything it references. + * No need to treat Constants with EnumTag (only used for Java + * annotations with Java enum parameters) */ - private def putConstant(c: Constant) = + private def putConstant(c: Constant) { if (putEntry(c)) { if (c.tag == StringTag) putEntry(newTermName(c.stringValue)) else if (c.tag == ClassTag) putType(c.typeValue) } + } private def putChildren(sym: Symbol, children: List[Symbol]) { assert(putEntry((sym, children))) children foreach putSymbol } + /** used in putSymbol only, i.e. annotations on definitions, not on types */ private def putAnnotation(sym: Symbol, annot: AnnotationInfo) { // if an annotation with the same arguments is applied to the // same symbol multiple times, it's only pickled once. - if (putEntry((sym, annot))) { - val AnnotationInfo(atp, args, assocs) = annot - putType(atp) - args foreach putAnnotationArg - for ((name, c) <- assocs) { putEntry(name); putAnnotationArg(c) } - } + if (putEntry((sym, annot))) + putAnnotationBody(annot) } + /** used in AnnotatedType only, i.e. annotations on types */ + private def putAnnotations(annots: List[AnnotationInfo]) { + annots foreach putAnnotation + } private def putAnnotation(annot: AnnotationInfo) { - if (putEntry(annot)) { - val AnnotationInfo(tpe, args, assocs) = annot - putType(tpe) - args foreach putAnnotationArg - for ((name, rhs) <- assocs) { putEntry(name); putAnnotationArg(rhs) } - } + if (putEntry(annot)) + putAnnotationBody(annot) } - private def putAnnotationArg(arg: AnnotationArgument) { - if (putEntry(arg)) { + /** Puts the members of an AnnotationInfo */ + private def putAnnotationBody(annot: AnnotationInfo) { + def putAnnotationArg(arg: AnnotationArgument) { arg.constant match { - case Some(c) => putConstant(c) - case _ => putTree(arg.intTree) - } + case Some(c) => putConstant(c) + case None => putTree(arg.intTree) + } + } + def putConstantAnnotationArg(carg: ConstantAnnotationArgument) { + carg match { + case LiteralAnnotationArgument(const) => + putConstant(const) + case ArrayAnnotationArgument(args) => + if (putEntry(carg)) + args foreach putConstantAnnotationArg + case NestedAnnotationArgument(annInfo) => + putAnnotation(annInfo) + } + } + val AnnotationInfo(tpe, args, assocs) = annot + putType(tpe) + args foreach putAnnotationArg + assocs foreach { asc => + putEntry(asc._1) + putConstantAnnotationArg(asc._2) } - } - - private def putAnnotations(annots: List[AnnotationInfo]) { - annots foreach putAnnotation } // Phase 2 methods: Write all entries to byte array ------------------------------ - private val buf = new PickleBuffer(new Array[Byte](4096), -1, 0) - /** Write a reference to object, i.e., the object's number in the map * <code>index</code>. * @@ -478,26 +493,50 @@ abstract class Pickler extends SubComponent { private def writeRefs(refs: List[AnyRef]) { refs foreach writeRef } /** Write name, owner, flags, and info of a symbol. - * - * @param sym ... - * @return the position offset */ - private def writeSymInfo(sym: Symbol): Int = { - var posOffset = 0 + private def writeSymInfo(sym: Symbol) { writeRef(sym.name) writeRef(normalizedOwner(sym)) writeLongNat((rawFlagsToPickled(sym.flags & PickledFlags))) if (sym.privateWithin != NoSymbol) writeRef(sym.privateWithin) writeRef(sym.info) - posOffset } /** Write a name in UTF8 format. */ - def writeName(name: Name) { + private def writeName(name: Name) { ensureCapacity(name.length * 3) writeIndex = name.copyUTF8(bytes, writeIndex) } + /** Write an annotation */ + private def writeAnnotation(annot: AnnotationInfo) { + def writeAnnotationArg(arg: AnnotationArgument) { + arg.constant match { + case Some(c) => writeRef(c) + case None => writeRef(arg.intTree) + } + } + + writeRef(annot.atp) + annot.args foreach writeAnnotationArg + annot.assocs foreach { asc => + writeRef(asc._1) + writeConstantAnnotationArg(asc._2) + } + } + + /** Write a ConstantAnnotationArgument (argument to java annotation) */ + def writeConstantAnnotationArg(carg: ConstantAnnotationArgument) { + carg match { + case LiteralAnnotationArgument(const) => + writeRef(const) + case ArrayAnnotationArgument(args) => + writeRef(carg) + case NestedAnnotationArgument(annInfo) => + writeRef(annInfo) + } + } + /** Write an entry */ private def writeEntry(entry: AnyRef) { def writeBody(entry: AnyRef): Int = entry match { @@ -516,18 +555,18 @@ abstract class Pickler extends SubComponent { if (!sym.owner.isRoot) writeRef(sym.owner) tag case sym: ClassSymbol => - val posOffset = writeSymInfo(sym) + writeSymInfo(sym) if (sym.thisSym.tpe != sym.tpe) writeRef(sym.typeOfThis) - CLASSsym + posOffset + CLASSsym case sym: TypeSymbol => - val posOffset = writeSymInfo(sym) - (if (sym.isAbstractType) TYPEsym else ALIASsym) + posOffset + writeSymInfo(sym) + if (sym.isAbstractType) TYPEsym else ALIASsym case sym: TermSymbol => if (!sym.isModule && sym.defaultGetter != NoSymbol) writeRef(sym.defaultGetter) - val posOffset = writeSymInfo(sym) + writeSymInfo(sym) if (sym.alias != NoSymbol) writeRef(sym.alias) - (if (sym.isModule) MODULEsym else VALsym) + posOffset + if (sym.isModule) MODULEsym else VALsym case NoType => NOtpe case NoPrefix => @@ -536,6 +575,8 @@ abstract class Pickler extends SubComponent { writeRef(sym); THIStpe case SingleType(pre, sym) => writeRef(pre); writeRef(sym); SINGLEtpe + case SuperType(thistpe, supertpe) => + writeRef(thistpe); writeRef(supertpe); SUPERtpe case ConstantType(value) => writeRef(value); CONSTANTtpe case TypeRef(pre, sym, args) => @@ -557,414 +598,396 @@ abstract class Pickler extends SubComponent { case DeBruijnIndex(l, i) => writeNat(l); writeNat(i); DEBRUIJNINDEXtpe case c @ Constant(_) => + // No case for Constant with EnumTag. See comment on "def putConstant" if (c.tag == BooleanTag) writeLong(if (c.booleanValue) 1 else 0) else if (ByteTag <= c.tag && c.tag <= LongTag) writeLong(c.longValue) else if (c.tag == FloatTag) writeLong(Float.floatToIntBits(c.floatValue)) else if (c.tag == DoubleTag) writeLong(Double.doubleToLongBits(c.doubleValue)) else if (c.tag == StringTag) writeRef(newTermName(c.stringValue)) else if (c.tag == ClassTag) writeRef(c.typeValue) - LITERAL + c.tag - case AnnotatedType(attribs, tp, selfsym) => - if (settings.selfInAnnots.value) { - writeRef(tp) - writeRef(selfsym) - writeRefs(attribs) - ANNOTATEDWSELFtpe - } else { + LITERAL + c.tag // also treats UnitTag, NullTag; no value required + case AnnotatedType(annotations, tp, selfsym) => + val staticAnnots = staticAnnotations(annotations) + if (staticAnnots isEmpty) { + writeBody(tp) // write the underlying type if there are no annotations + } else { + if (settings.selfInAnnots.value && selfsym != NoSymbol) + writeRef(selfsym) writeRef(tp) - writeRefs(attribs) + writeRefs(staticAnnots) ANNOTATEDtpe - } - case (target: Symbol, attr @ AnnotationInfo(atp, args, assocs)) => + } + + // annotations attached to a symbol (i.e. annots on terms) + case (target: Symbol, annot@AnnotationInfo(_, _, _)) => writeRef(target) - writeRef(atp) - for (c <- args) writeRef(c) - for ((name, c) <- assocs) { writeRef(name); writeRef(c) } - ATTRIBUTE - case (target: Symbol, children: List[_]) => + writeAnnotation(annot) + SYMANNOT + + case ArrayAnnotationArgument(args) => + args foreach writeConstantAnnotationArg + ANNOTARGARRAY + + case (target: Symbol, children: List[Symbol]) => writeRef(target) for (c <- children) writeRef(c.asInstanceOf[Symbol]) CHILDREN - case EmptyTree => - writeNat(EMPTYtree) - TREE + case EmptyTree => + writeNat(EMPTYtree) + TREE - case tree@PackageDef(name, stats) => - writeNat(PACKAGEtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(tree.mods) - writeRef(name) + case tree@PackageDef(name, stats) => + writeNat(PACKAGEtree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(tree.mods) + writeRef(name) writeRefs(stats) - TREE - - case tree@ClassDef(mods, name, tparams, impl) => - writeNat(CLASStree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(mods) - writeRef(name) + TREE + + case tree@ClassDef(mods, name, tparams, impl) => + writeNat(CLASStree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(mods) + writeRef(name) writeRef(impl) - writeRefs(tparams) - TREE - - case tree@ModuleDef(mods, name, impl) => - writeNat(MODULEtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(mods) - writeRef(name) - writeRef(impl) - TREE - - case tree@ValDef(mods, name, tpt, rhs) => - writeNat(VALDEFtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(mods) - writeRef(name) - writeRef(tpt) - writeRef(rhs) - TREE + writeRefs(tparams) + TREE + case tree@ModuleDef(mods, name, impl) => + writeNat(MODULEtree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(mods) + writeRef(name) + writeRef(impl) + TREE - case tree@DefDef(mods, name, tparams, vparamss, tpt, rhs) => + case tree@ValDef(mods, name, tpt, rhs) => + writeNat(VALDEFtree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(mods) + writeRef(name) + writeRef(tpt) + writeRef(rhs) + TREE + + case tree@DefDef(mods, name, tparams, vparamss, tpt, rhs) => writeNat(DEFDEFtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(mods) - writeRef(name) - writeNat(tparams.length) - writeRefs(tparams) - writeNat(vparamss.length) - for(vparams <- vparamss) { - writeNat(vparams.length) - writeRefs(vparams) - } - writeRef(tpt) - writeRef(rhs) - TREE - - - case tree@TypeDef(mods, name, tparams, rhs) => - writeNat(TYPEDEFtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(mods) - writeRef(name) - writeRef(rhs) - writeRefs(tparams) - TREE - - - case tree@LabelDef(name, params, rhs) => - writeNat(LABELtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(name) - writeRef(rhs) - writeRefs(params) - TREE - - - case tree@Import(expr, selectors) => - writeNat(IMPORTtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(expr) - for ((from, to) <- selectors) { - writeRef(from) - writeRef(to) - } - TREE - - - case tree@Annotation(constr, elements) => - writeNat(ANNOTATIONtree) - writeRef(tree.tpe) - writeRef(constr) - writeRefs(elements) - TREE - - case tree@DocDef(comment, definition) => + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(mods) + writeRef(name) + writeNat(tparams.length) + writeRefs(tparams) + writeNat(vparamss.length) + for(vparams <- vparamss) { + writeNat(vparams.length) + writeRefs(vparams) + } + writeRef(tpt) + writeRef(rhs) + TREE + + case tree@TypeDef(mods, name, tparams, rhs) => + writeNat(TYPEDEFtree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(mods) + writeRef(name) + writeRef(rhs) + writeRefs(tparams) + TREE + + case tree@LabelDef(name, params, rhs) => + writeNat(LABELtree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(name) + writeRef(rhs) + writeRefs(params) + TREE + + case tree@Import(expr, selectors) => + writeNat(IMPORTtree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(expr) + for ((from, to) <- selectors) { + writeRef(from) + writeRef(to) + } + TREE + + case tree@DocDef(comment, definition) => writeNat(DOCDEFtree) - writeRef(tree.tpe) - writeRef(Constant(comment)) - writeRef(definition) - TREE + writeRef(tree.tpe) + writeRef(Constant(comment)) + writeRef(definition) + TREE - case tree@Template(parents, self, body) => + case tree@Template(parents, self, body) => writeNat(TEMPLATEtree) - writeRef(tree.tpe) + writeRef(tree.tpe) writeRef(tree.symbol) writeNat(parents.length) - writeRefs(parents) - writeRef(self) - writeRefs(body) - TREE + writeRefs(parents) + writeRef(self) + writeRefs(body) + TREE - case tree@Block(stats, expr) => + case tree@Block(stats, expr) => writeNat(BLOCKtree) - writeRef(tree.tpe) - writeRef(expr) - writeRefs(stats) - TREE - - case tree@CaseDef(pat, guard, body) => - writeNat(CASEtree) - writeRef(tree.tpe) - writeRef(pat) - writeRef(guard) - writeRef(body) - TREE - - case tree@Sequence(trees) => + writeRef(tree.tpe) + writeRef(expr) + writeRefs(stats) + TREE + + case tree@CaseDef(pat, guard, body) => + writeNat(CASEtree) + writeRef(tree.tpe) + writeRef(pat) + writeRef(guard) + writeRef(body) + TREE + + case tree@Sequence(trees) => writeNat(SEQUENCEtree) - writeRef(tree.tpe) - writeRefs(trees) - TREE + writeRef(tree.tpe) + writeRefs(trees) + TREE - case tree@Alternative(trees) => - writeNat(ALTERNATIVEtree) - writeRef(tree.tpe) - writeRefs(trees) - TREE + case tree@Alternative(trees) => + writeNat(ALTERNATIVEtree) + writeRef(tree.tpe) + writeRefs(trees) + TREE - case tree@Star(elem) => + case tree@Star(elem) => writeNat(STARtree) - writeRef(tree.tpe) - writeRef(elem) - TREE - - case tree@Bind(name, body) => - writeNat(BINDtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(name) - writeRef(body) - TREE - - case tree@UnApply(fun: Tree, args) => - writeNat(UNAPPLYtree) - writeRef(tree.tpe) - writeRef(fun) - writeRefs(args) - TREE - - case tree@ArrayValue(elemtpt, trees) => - writeNat(ARRAYVALUEtree) - writeRef(tree.tpe) - writeRef(elemtpt) - writeRefs(trees) - TREE - - - case tree@Function(vparams, body) => + writeRef(tree.tpe) + writeRef(elem) + TREE + + case tree@Bind(name, body) => + writeNat(BINDtree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(name) + writeRef(body) + TREE + + case tree@UnApply(fun: Tree, args) => + writeNat(UNAPPLYtree) + writeRef(tree.tpe) + writeRef(fun) + writeRefs(args) + TREE + + case tree@ArrayValue(elemtpt, trees) => + writeNat(ARRAYVALUEtree) + writeRef(tree.tpe) + writeRef(elemtpt) + writeRefs(trees) + TREE + + + case tree@Function(vparams, body) => writeNat(FUNCTIONtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(body) - writeRefs(vparams) - TREE + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(body) + writeRefs(vparams) + TREE - case tree@Assign(lhs, rhs) => + case tree@Assign(lhs, rhs) => writeNat(ASSIGNtree) - writeRef(tree.tpe) - writeRef(lhs) - writeRef(rhs) - TREE + writeRef(tree.tpe) + writeRef(lhs) + writeRef(rhs) + TREE - case tree@If(cond, thenp, elsep) => + case tree@If(cond, thenp, elsep) => writeNat(IFtree) writeRef(tree.tpe) - writeRef(cond) - writeRef(thenp) - writeRef(elsep) - TREE + writeRef(cond) + writeRef(thenp) + writeRef(elsep) + TREE - case tree@Match(selector, cases) => + case tree@Match(selector, cases) => writeNat(MATCHtree) - writeRef(tree.tpe) - writeRef(selector) - writeRefs(cases) - TREE - - case tree@Return(expr) => - writeNat(RETURNtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(expr) - TREE - - case tree@Try(block, catches, finalizer) => + writeRef(tree.tpe) + writeRef(selector) + writeRefs(cases) + TREE + + case tree@Return(expr) => + writeNat(RETURNtree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(expr) + TREE + + case tree@Try(block, catches, finalizer) => writeNat(TREtree) - writeRef(tree.tpe) - writeRef(block) - writeRef(finalizer) - writeRefs(catches) - TREE - - case tree@Throw(expr) => - writeNat(THROWtree) - writeRef(tree.tpe) - writeRef(expr) - TREE - - case tree@New(tpt) => - writeNat(NEWtree) - writeRef(tree.tpe) - writeRef(tpt) - TREE - - case tree@Typed(expr, tpt) => - writeNat(TYPEDtree) - writeRef(tree.tpe) - writeRef(expr) - writeRef(tpt) - TREE - - case tree@TypeApply(fun, args) => - writeNat(TYPEAPPLYtree) - writeRef(tree.tpe) - writeRef(fun) - writeRefs(args) - TREE - - case tree@Apply(fun, args) => - writeNat(APPLYtree) - writeRef(tree.tpe) - writeRef(fun) - writeRefs(args) - TREE - - case tree@ApplyDynamic(qual, args) => - writeNat(APPLYDYNAMICtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(qual) - writeRefs(args) - TREE - - case tree@Super(qual, mix) => - writeNat(SUPERtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(qual) - writeRef(mix) - TREE + writeRef(tree.tpe) + writeRef(block) + writeRef(finalizer) + writeRefs(catches) + TREE + + case tree@Throw(expr) => + writeNat(THROWtree) + writeRef(tree.tpe) + writeRef(expr) + TREE + + case tree@New(tpt) => + writeNat(NEWtree) + writeRef(tree.tpe) + writeRef(tpt) + TREE + + case tree@Typed(expr, tpt) => + writeNat(TYPEDtree) + writeRef(tree.tpe) + writeRef(expr) + writeRef(tpt) + TREE + + case tree@TypeApply(fun, args) => + writeNat(TYPEAPPLYtree) + writeRef(tree.tpe) + writeRef(fun) + writeRefs(args) + TREE + + case tree@Apply(fun, args) => + writeNat(APPLYtree) + writeRef(tree.tpe) + writeRef(fun) + writeRefs(args) + TREE + + case tree@ApplyDynamic(qual, args) => + writeNat(APPLYDYNAMICtree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(qual) + writeRefs(args) + TREE + + case tree@Super(qual, mix) => + writeNat(SUPERtree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(qual) + writeRef(mix) + TREE case tree@This(qual) => - writeNat(THIStree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(qual) - TREE + writeNat(THIStree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(qual) + TREE case tree@Select(qualifier, selector) => - writeNat(SELECTtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(qualifier) - writeRef(selector) - TREE - - case tree@Ident(name) => - writeNat(IDENTtree) - writeRef(tree.tpe) - writeRef(tree.symbol) - writeRef(name) - TREE - - case tree@Literal(value) => - writeNat(LITERALtree) - writeRef(tree.tpe) - writeRef(value) - TREE - - case tree@TypeTree() => - writeNat(TYPEtree) - writeRef(tree.tpe) - TREE - - case tree@Annotated(annot, arg) => - writeNat(ANNOTATEDtree) - writeRef(tree.tpe) - writeRef(annot) - writeRef(arg) - TREE - - case tree@SingletonTypeTree(ref) => - writeNat(SINGLETONTYPEtree) - writeRef(tree.tpe) - writeRef(ref) - TREE - - case tree@SelectFromTypeTree(qualifier, selector) => - writeNat(SELECTFROMTYPEtree) - writeRef(tree.tpe) - writeRef(qualifier) - writeRef(selector) - TREE - - case tree@CompoundTypeTree(templ: Template) => - writeNat(COMPOUNDTYPEtree) - writeRef(tree.tpe) - writeRef(templ) - TREE - - case tree@AppliedTypeTree(tpt, args) => - writeNat(APPLIEDTYPEtree) - writeRef(tree.tpe) - writeRef(tpt) - writeRefs(args) - TREE - - case tree@TypeBoundsTree(lo, hi) => - writeNat(TYPEBOUNDStree) - writeRef(tree.tpe) - writeRef(lo) - writeRef(hi) - TREE - - case tree@ExistentialTypeTree(tpt, whereClauses) => - writeNat(EXISTENTIALTYPEtree) - writeRef(tree.tpe) - writeRef(tpt) - writeRefs(whereClauses) - TREE - - - case Modifiers(flags, privateWithin, annotations) => + writeNat(SELECTtree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(qualifier) + writeRef(selector) + TREE + + case tree@Ident(name) => + writeNat(IDENTtree) + writeRef(tree.tpe) + writeRef(tree.symbol) + writeRef(name) + TREE + + case tree@Literal(value) => + writeNat(LITERALtree) + writeRef(tree.tpe) + writeRef(value) + TREE + + case tree@TypeTree() => + writeNat(TYPEtree) + writeRef(tree.tpe) + TREE + + case tree@Annotated(annot, arg) => + writeNat(ANNOTATEDtree) + writeRef(tree.tpe) + writeRef(annot) + writeRef(arg) + TREE + + case tree@SingletonTypeTree(ref) => + writeNat(SINGLETONTYPEtree) + writeRef(tree.tpe) + writeRef(ref) + TREE + + case tree@SelectFromTypeTree(qualifier, selector) => + writeNat(SELECTFROMTYPEtree) + writeRef(tree.tpe) + writeRef(qualifier) + writeRef(selector) + TREE + + case tree@CompoundTypeTree(templ: Template) => + writeNat(COMPOUNDTYPEtree) + writeRef(tree.tpe) + writeRef(templ) + TREE + + case tree@AppliedTypeTree(tpt, args) => + writeNat(APPLIEDTYPEtree) + writeRef(tree.tpe) + writeRef(tpt) + writeRefs(args) + TREE + + case tree@TypeBoundsTree(lo, hi) => + writeNat(TYPEBOUNDStree) + writeRef(tree.tpe) + writeRef(lo) + writeRef(hi) + TREE + + case tree@ExistentialTypeTree(tpt, whereClauses) => + writeNat(EXISTENTIALTYPEtree) + writeRef(tree.tpe) + writeRef(tpt) + writeRefs(whereClauses) + TREE + + case Modifiers(flags, privateWithin, annotations) => val pflags = rawFlagsToPickled(flags) - writeNat((pflags >> 32).toInt) - writeNat((pflags & 0xFFFFFFFF).toInt) - writeRef(privateWithin) - writeRefs(annotations) - MODIFIERS - - case AnnotationInfo(atp, args, assocs) => - writeRef(atp) - writeNat(args.length) - for (arg <- args) writeRef(arg) - for ((name, arg) <- assocs) { - writeRef(name); - writeRef(arg) - } + writeNat((pflags >> 32).toInt) + writeNat((pflags & 0xFFFFFFFF).toInt) + writeRef(privateWithin) + MODIFIERS + + // annotations on types (not linked to a symbol) + case annot@AnnotationInfo(_, _, _) => + writeAnnotation(annot) ANNOTINFO - case arg:AnnotationArgument => - arg.constant match { - case Some(c) => writeBody(c) - case None => writeBody(arg.intTree) - } - case _ => throw new FatalError("bad entry: " + entry + " " + entry.getClass) } // begin writeEntry val startpos = writeIndex + // reserve some space so that the patchNat's most likely won't need to shift writeByte(0); writeByte(0) patchNat(startpos, writeBody(entry)) patchNat(startpos + 1, writeIndex - (startpos + 2)) @@ -1048,27 +1071,30 @@ abstract class Pickler extends SubComponent { else if (c.tag == DoubleTag) print("Double "+c.doubleValue) else if (c.tag == StringTag) { print("String "); printRef(newTermName(c.stringValue)) } else if (c.tag == ClassTag) { print("Class "); printRef(c.typeValue) } - case AnnotatedType(attribs, tp, selfsym) => - if (settings.selfInAnnots.value) { + case AnnotatedType(annots, tp, selfsym) => + if (settings.selfInAnnots.value) { print("ANNOTATEDWSELFtpe ") - printRef(tp) - printRef(selfsym) - printRefs(attribs) - } else { + printRef(tp) + printRef(selfsym) + printRefs(annots) + } else { print("ANNOTATEDtpe ") printRef(tp) - printRefs(attribs) - } - case (target: Symbol, attr @ AnnotationInfo(atp, args, assocs)) => - print("ATTRIBUTE ") + printRefs(annots) + } + case (target: Symbol, AnnotationInfo(atp, args, Nil)) => + print("SYMANNOT ") printRef(target) printRef(atp) for (c <- args) printRef(c) - for ((name, c) <- assocs) { printRef(name); printRef(c) } case (target: Symbol, children: List[_]) => print("CHILDREN ") printRef(target) for (c <- children) printRef(c.asInstanceOf[Symbol]) + case AnnotationInfo(atp, args, Nil) => + print("ANNOTINFO") + printRef(atp) + for (c <- args) printRef(c) case _ => throw new FatalError("bad entry: " + entry + " " + entry.getClass) } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala index 1fc87fa3a7..853a2d0ca0 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/UnPickler.scala @@ -47,6 +47,8 @@ abstract class UnPickler { private class UnPickle(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) extends PickleBuffer(bytes, offset, -1) { if (settings.debug.value) global.log("unpickle " + classRoot + " and " + moduleRoot) + var major = 0 + var minor = 0 checkVersion(filename) /** A map from entry numbers to array offsets */ @@ -59,15 +61,19 @@ abstract class UnPickler { private val symScopes = new HashMap[Symbol, Scope] for (i <- 0 until index.length) { - if (isSymbolEntry(i)) { at(i, readSymbol); {} } - else if (isAnnotationEntry(i)) { at(i, readAnnotation); {} } + if (isSymbolEntry(i)) + at(i, readSymbol) + else if (isSymbolAnnotationEntry(i)) + at(i, {() => if (major == 4) readOldSymbolAnnotation() else readSymbolAnnotation(); null}) //@LUC todo remove for 2.8 + else if (isChildrenEntry(i)) + at(i, {() => readChildren(); null}) } if (settings.debug.value) global.log("unpickled " + classRoot + ":" + classRoot.rawInfo + ", " + moduleRoot + ":" + moduleRoot.rawInfo);//debug private def checkVersion(filename: String) { - val major = readNat() - val minor = readNat() + major = readNat() + minor = readNat() // remove the portion below, between "cut here", before releasing the first 2.8 beta @@ -106,14 +112,14 @@ abstract class UnPickler { /** Does entry represent an (internal) symbol */ private def isSymbolEntry(i: Int): Boolean = { - val tag = bytes(index(i)) % PosOffset + val tag = bytes(index(i)) % PosOffset // @LUC TODO remove posOffset by 2.8.0 (firstSymTag <= tag && tag <= lastSymTag && (tag != CLASSsym || !isRefinementSymbolEntry(i))) } /** Does entry represent an (internal or external) symbol */ private def isSymbolRef(i: Int): Boolean = { - val tag = bytes(index(i)) % PosOffset + val tag = bytes(index(i)) % PosOffset // @LUC TODO remove posOffset by 2.8.0 (firstSymTag <= tag && tag <= lastExtSymTag) } @@ -123,10 +129,16 @@ abstract class UnPickler { tag == TERMname || tag == TYPEname } - /** Does entry represent a symbol attribute? */ - private def isAnnotationEntry(i: Int): Boolean = { + /** Does entry represent a symbol annotation? */ + private def isSymbolAnnotationEntry(i: Int): Boolean = { val tag = bytes(index(i)) - tag == ATTRIBUTE || tag == CHILDREN + tag == SYMANNOT + } + + /** Does the entry represent children of a symbol? */ + private def isChildrenEntry(i: Int): Boolean = { + val tag = bytes(index(i)) + tag == CHILDREN } /** Does entry represent a refinement symbol? @@ -136,9 +148,9 @@ abstract class UnPickler { val savedIndex = readIndex readIndex = index(i) val tag = readByte() - if (tag % PosOffset != CLASSsym) assert(false) + if (tag % PosOffset != CLASSsym) assert(false) // @LUC TODO remove posOffset by 2.8.0 readNat(); // read length - if (tag > PosOffset) readNat(); // read position + if (tag > PosOffset) readNat(); // @LUC TODO read position, remove posOffset by 2.8.0 val result = readNameRef() == nme.REFINE_CLASS_NAME.toTypeName readIndex = savedIndex result @@ -185,14 +197,20 @@ abstract class UnPickler { else if (name == nme.ROOTPKG) definitions.RootPackage else if (tag == EXTref) owner.info.decl(name) else owner.info.decl(name).moduleClass - if (sym == NoSymbol) { + + // If the owner is overloaded (i.e. a method), it's not possible to select the + // right member => return NoSymbol. This can only happen when unpickling a tree. + // the "case Apply" in readTree() takes care of selecting the correct alternative + // after parsing the arguments. + if (sym == NoSymbol && !owner.hasFlag(OVERLOADED)) { errorBadSignature( "reference " + (if (name.isTypeName) "type " else "value ") + name.decode + " of " + owner + " refers to nonexisting symbol.") } case NONEsym => sym = NoSymbol - case _ => + case _ => // symbols that were pickled with Pickler.writeSymInfo + // @LUC TODO remove posOffset by 2.8.0 val unusedPos : Int = { if (tag > PosOffset) readNat else -1 @@ -212,7 +230,7 @@ abstract class UnPickler { privateWithin = at(inforef, readSymbol) inforef = readNat() } - (tag % PosOffset) match { + (tag % PosOffset) match { // @LUC TODO remove posOffset by 2.8.0 case TYPEsym => sym = owner.newAbstractType(NoPosition, name) case ALIASsym => @@ -291,6 +309,10 @@ abstract class UnPickler { mkThisType(readSymbolRef()) case SINGLEtpe => singleType(readTypeRef(), readSymbolRef()) + case SUPERtpe => + val thistpe = readTypeRef() + val supertpe = readTypeRef() + SuperType(thistpe, supertpe) case CONSTANTtpe => mkConstantType(readConstantRef()) case TYPEREFtpe => @@ -317,24 +339,35 @@ abstract class UnPickler { val restpe = readTypeRef() // compatibility with old format. TODO replace by "until(end, readSymbolRef)" val params = readMethodParams(false, end) - MethodType(params, restpe) + // if the method is overloaded, the params cannot be determined (see readSymbol) => return NoType. + // Only happen for trees, "case Apply" in readTree() takes care of selecting the correct + // alternative after parsing the arguments. + if (params.contains(NoSymbol) || restpe == NoType) NoType + else MethodType(params, restpe) case IMPLICITMETHODtpe => val restpe = readTypeRef() val params = readMethodParams(true, end) ImplicitMethodType(params, restpe) case POLYtpe => val restpe = readTypeRef() - PolyType(until(end, readSymbolRef), restpe) + val typeParams = until(end, readSymbolRef) + // see comment above in "case METHODtpe" + if (typeParams.contains(NoSymbol) || restpe == NoType) NoType + else PolyType(typeParams, restpe) case EXISTENTIALtpe => val restpe = readTypeRef() ExistentialType(until(end, readSymbolRef), restpe) - case ANNOTATEDtpe | ANNOTATEDWSELFtpe => - val tp = readTypeRef() - val selfsym = if (tag == ANNOTATEDWSELFtpe) readSymbolRef() - else NoSymbol - val attribs = until(end, readTreeAttribRef) - if (settings.selfInAnnots.value || (selfsym eq NoSymbol)) - AnnotatedType(attribs, tp, selfsym) + case ANNOTATEDtpe => + var typeRef = readNat() + val selfsym = if (isSymbolRef(typeRef)) { + val s = at(typeRef, readSymbol) + typeRef = readNat() + s + } else NoSymbol + val tp = at(typeRef, readType) + val annots = until(end, readAnnotationRef) + if (settings.selfInAnnots.value || (selfsym == NoSymbol)) + AnnotatedType(annots, tp, selfsym) else tp // drop annotations with a self symbol unless // -Yself-in-annots is on @@ -366,376 +399,436 @@ abstract class UnPickler { } } - /** Read an annotation argument. It can use either Constant's or - * Tree's for its arguments. If a reflect tree is seen, it - * prints a warning and returns an empty tree. + /** Read children and store them into the corresponding symbol. + */ + private def readChildren() { + val tag = readByte() + assert(tag == CHILDREN) + val end = readNat() + readIndex + val target = readSymbolRef() + while (readIndex != end) target addChild readSymbolRef() + } + + /** Read an annotation argument. It can use either Constant's or + * Tree's for its arguments. */ private def readAnnotationArg(): AnnotationArgument = { + // @LUC TODO Warning about reflection trees in pickle. Remove for 2.8.0 if (peekByte() == REFLTREE) { reflectAnnotationWarning() - new AnnotationArgument(EmptyTree) + new AnnotationArgument(EmptyTree) } else if (peekByte() == TREE) { - val tree = readTree() - new AnnotationArgument(tree) + val tree = readTree() + new AnnotationArgument(tree) } else { val const = readConstant() new AnnotationArgument(const) } } - /** Read an annotation abstract syntax tree. */ - private def readAnnotationTree(): Annotation = { + /** Read a ConstantAnnotationArgument (argument to a java annotation) + */ + private def readConstantAnnotationArg(): ConstantAnnotationArgument = { + val b = peekByte() + if (peekByte() == ANNOTINFO) { + NestedAnnotationArgument(readAnnotation()) + } else if (peekByte() == ANNOTARGARRAY) { + readByte() + val end = readNat() + readIndex + ArrayAnnotationArgument(until(end, readConstantAnnotationArgRef).toArray) + } else { + LiteralAnnotationArgument(readConstant()) + } + } + + /** Read an AnnotationInfo. Not to be called directly, use + * readAnnotation or readSymbolAnnotation + */ + private def readAnnotationInfo(end: Int): AnnotationInfo = { + val atp = readTypeRef() + //val args = until(end, readAnnotationArgRef) + //AnnotationInfo(atp, args, List()) + val args = new ListBuffer[AnnotationArgument] + val assocs = new ListBuffer[(Name, ConstantAnnotationArgument)] + while (readIndex != end) { + val argref = readNat() + if (isNameEntry(argref)) + assocs += ((at(argref, readName), readConstantAnnotationArgRef)) + else + args += at(argref, readAnnotationArg) + } + AnnotationInfo(atp, args.toList, assocs.toList) + } + + /** Old-style annotation infos. Deprecated in June 2008, + * @LUC TODO remove for 2.8.0 + */ + private def readOldAnnotationInfo(end: Int): AnnotationInfo = { + val atp = readTypeRef() + val numargs = readNat() + val args = times(numargs, readAnnotationArgRef) + val assocs = + until(end, () => { + val name = readNameRef() + val arg = readAnnotationArgRef + (name, arg)}) + AnnotationInfo(atp, args, List()) + } + + /** Read an annotation and as a side effect store it into + * the symbol it requests. Called at top-level, for all + * (symbol, annotInfo) entries. */ + private def readSymbolAnnotation() { val tag = readByte() + if (tag != SYMANNOT) + errorBadSignature("symbol annotation expected ("+ tag +")") val end = readNat() + readIndex - val tpe = readTypeRef() - val constr = readTreeRef() - val elements = until(end, readTreeRef) - Annotation(constr, elements).setType(tpe) + val target = readSymbolRef() + target.addAnnotation(readAnnotationInfo(end)) } - /** Read an attribute and as a side effect store it into - * the symbol it requests. */ - private def readAnnotation(): AnyRef = { + /** @LUC TODO Old-style symbol annotations, deprecated by June 2008, remove for 2.8.0 */ + private def readOldSymbolAnnotation() { val tag = readByte() + if (tag != SYMANNOT) + errorBadSignature("symbol annotation expected ("+ tag +")") val end = readNat() + readIndex val target = readSymbolRef() - if (tag == ATTRIBUTE) { - val attrType = readTypeRef() - val args = new ListBuffer[AnnotationArgument] - val assocs = new ListBuffer[(Name, AnnotationArgument)] - while (readIndex != end) { - val argref = readNat() - 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 - } else if (tag == CHILDREN) { - while (readIndex != end) target addChild readSymbolRef() + val attrType = readTypeRef() + val args = new ListBuffer[AnnotationArgument] + val assocs = new ListBuffer[(Name, AnnotationArgument)] + while (readIndex != end) { + val argref = readNat() + if (isNameEntry(argref)) + assocs += ((at(argref, readName), readAnnotationArgRef)) + else + args += at(argref, readAnnotationArg) } - null + val attr = AnnotationInfo(attrType, args.toList, List()) + target.addAnnotation(attr) } - /** Read an annotation and return it. */ - private def readTreeAttrib(): AnnotationInfo = { + /** Read an annotation and return it. Only called when + * unpickling an ANNOTATED(WSELF)tpe. */ + private def readAnnotation(): AnnotationInfo = { val tag = readByte() - if(tag != ANNOTINFO) - errorBadSignature("tree-based annotation expected (" + tag + ")") + if (tag != ANNOTINFO) + errorBadSignature("annotation expected (" + tag + ")") val end = readNat() + readIndex - - val atp = readTypeRef() - val numargs = readNat() - val args = times(numargs, readAnnotationArgRef) - val assocs = - until(end, {() => - val name = readNameRef() - val tree = readAnnotationArgRef() - (name,tree)}) - AnnotationInfo(atp, args, assocs) + if (major == 4) { // @LUC TODO deprecated by June 2008, remove for 2.8.0 + readOldAnnotationInfo(end) + } else { + readAnnotationInfo(end) + } } + private def readTree(): Tree = readTree(false) // @LUC TODO remove + /* Read an abstract syntax tree */ - private def readTree(): Tree = { + private def readTree(skipTag: Boolean): Tree = { + if (!skipTag) { // @LUC TODO remove skipTag val outerTag = readByte() if (outerTag != TREE) - errorBadSignature("tree expected (" + outerTag + ")") + errorBadSignature("tree expected (" + outerTag + ")") + } val end = readNat() + readIndex val tag = readByte() val tpe = - if (tag != EMPTYtree) - readTypeRef() - else - NoType + if (tag != EMPTYtree) + readTypeRef() + else + NoType tag match { - case EMPTYtree => - EmptyTree + case EMPTYtree => + EmptyTree + + case PACKAGEtree => + val symbol = readSymbolRef() + val name = readNameRef() + val stats = until(end, readTreeRef) + PackageDef(name, stats) setType tpe - case PACKAGEtree => - val symbol = readSymbolRef() - val name = readNameRef() - val stats = until(end, readTreeRef) + case CLASStree => + val symbol = readSymbolRef() + val mods = readModifiersRef() + val name = readNameRef() + val impl = readTemplateRef() + val tparams = until(end, readTypeDefRef) + (ClassDef(mods, name, tparams, impl). + setSymbol(symbol). + setType(tpe)) - PackageDef(name, stats) setType tpe + case MODULEtree => + val symbol = readSymbolRef() + val mods = readModifiersRef() + val name = readNameRef() + val impl = readTemplateRef() + (ModuleDef(mods, name, impl). + setSymbol(symbol). + setType(tpe)) - case CLASStree => - val symbol = readSymbolRef() + case VALDEFtree => + val symbol = readSymbolRef() val mods = readModifiersRef() - val name = readNameRef() - val impl = readTemplateRef() - val tparams = until(end, readTypeDefRef) - (ClassDef(mods, name, tparams, impl). - setSymbol(symbol). - setType(tpe)) - - case MODULEtree => - val symbol = readSymbolRef() - val mods = readModifiersRef() - val name = readNameRef() - val impl = readTemplateRef() - (ModuleDef(mods, name, impl). - setSymbol(symbol). - setType(tpe)) - - case VALDEFtree => - val symbol = readSymbolRef() - val mods = readModifiersRef() - val name = readNameRef() - val tpt = readTreeRef() - val rhs = readTreeRef() - - (ValDef(mods, name, tpt, rhs). - setSymbol(symbol). - setType(tpe)) - - case DEFDEFtree => - val symbol = readSymbolRef() - val mods = readModifiersRef() - val name = readNameRef() - val numTparams = readNat() - val tparams = times(numTparams, readTypeDefRef) - val numVparamss = readNat - val vparamss = times(numVparamss, () => { - val len = readNat() - times(len, readValDefRef)}) - val tpt = readTreeRef() - val rhs = readTreeRef() - - (DefDef(mods, name, tparams, vparamss, tpt, rhs). - setSymbol(symbol). - setType(tpe)) - - case TYPEDEFtree => + val name = readNameRef() + val tpt = readTreeRef() + val rhs = readTreeRef() + + (ValDef(mods, name, tpt, rhs). + setSymbol(symbol). + setType(tpe)) + + case DEFDEFtree => val symbol = readSymbolRef() - val mods = readModifiersRef() - val name = readNameRef() - val rhs = readTreeRef() - val tparams = until(end, readTypeDefRef) + val mods = readModifiersRef() + val name = readNameRef() + val numTparams = readNat() + val tparams = times(numTparams, readTypeDefRef) + val numVparamss = readNat + val vparamss = times(numVparamss, () => { + val len = readNat() + times(len, readValDefRef)}) + val tpt = readTreeRef() + val rhs = readTreeRef() - (TypeDef(mods, name, tparams, rhs). - setSymbol(symbol). - setType(tpe)) + (DefDef(mods, name, tparams, vparamss, tpt, rhs). + setSymbol(symbol). + setType(tpe)) + case TYPEDEFtree => + val symbol = readSymbolRef() + val mods = readModifiersRef() + val name = readNameRef() + val rhs = readTreeRef() + val tparams = until(end, readTypeDefRef) + + (TypeDef(mods, name, tparams, rhs). + setSymbol(symbol). + setType(tpe)) - case LABELtree => - val symbol = readSymbolRef() - val name = readNameRef() - val rhs = readTreeRef() - val params = until(end, readIdentRef) + case LABELtree => + val symbol = readSymbolRef() + val name = readNameRef() + val rhs = readTreeRef() + val params = until(end, readIdentRef) (LabelDef(name, params, rhs). - setSymbol(symbol). - setType(tpe)) + setSymbol(symbol). + setType(tpe)) + + case IMPORTtree => + val symbol = readSymbolRef() + val expr = readTreeRef() + val selectors = until(end, () => { + val from = readNameRef() + val to = readNameRef() + (from, to) + }) + (Import(expr, selectors). + setSymbol(symbol). + setType(tpe)) + + // @LUC TODO remove for 2.8.0 (no longer pickled) + case ANNOTATIONtree => + val constr = readTreeRef() + val elements = until(end, readTreeRef) + //(Annotation(constr, elements).setType(tpe)) + EmptyTree + + case DOCDEFtree => + val comment = readConstantRef match { + case Constant(com: String) => com + case other => + errorBadSignature("Document comment not a string (" + other + ")") + } + val definition = readTreeRef() + (DocDef(comment, definition).setType(tpe)) - case IMPORTtree => + case TEMPLATEtree => val symbol = readSymbolRef() - val expr = readTreeRef() - val selectors = until(end, () => { - val from = readNameRef() - val to = readNameRef() - (from, to) - }) - (Import(expr, selectors). - setSymbol(symbol). - setType(tpe)) - - case ANNOTATIONtree => - val constr = readTreeRef() - val elements = until(end, readTreeRef) - (Annotation(constr, elements).setType(tpe)) - - case DOCDEFtree => - val comment = readConstantRef match { - case Constant(com: String) => com - case other => - errorBadSignature("Document comment not a string (" + other + ")") - } - val definition = readTreeRef() - (DocDef(comment, definition).setType(tpe)) - - case TEMPLATEtree => - val symbol = readSymbolRef() val numParents = readNat() - val parents = times(numParents, readTreeRef) - val self = readValDefRef() - val body = until(end, readTreeRef) - - (Template(parents, self, body). - setSymbol(symbol). - setType(tpe)) - - case BLOCKtree => - val expr = readTreeRef() - val stats = until(end, readTreeRef) - Block(stats, expr).setType(tpe) - - case CASEtree => - val pat = readTreeRef() - val guard = readTreeRef() - val body = readTreeRef() - CaseDef(pat, guard, body).setType(tpe) - - case SEQUENCEtree => - val trees = until(end, readTreeRef) - Sequence(trees).setType(tpe) - - case ALTERNATIVEtree => - val trees = until(end, readTreeRef) - Alternative(trees).setType(tpe) - - case STARtree => - val elem = readTreeRef() - Star(elem).setType(tpe) - - case BINDtree => - val symbol = readSymbolRef() - val name = readNameRef() - val body = readTreeRef() - (Bind(name, body). - setSymbol(symbol). - setType(tpe)) - - case UNAPPLYtree => - val fun = readTreeRef() - val args = until(end, readTreeRef) + val parents = times(numParents, readTreeRef) + val self = readValDefRef() + val body = until(end, readTreeRef) + + (Template(parents, self, body). + setSymbol(symbol). + setType(tpe)) + + case BLOCKtree => + val expr = readTreeRef() + val stats = until(end, readTreeRef) + Block(stats, expr).setType(tpe) + + case CASEtree => + val pat = readTreeRef() + val guard = readTreeRef() + val body = readTreeRef() + CaseDef(pat, guard, body).setType(tpe) + + case SEQUENCEtree => + val trees = until(end, readTreeRef) + Sequence(trees).setType(tpe) + + case ALTERNATIVEtree => + val trees = until(end, readTreeRef) + Alternative(trees).setType(tpe) + + case STARtree => + val elem = readTreeRef() + Star(elem).setType(tpe) + + case BINDtree => + val symbol = readSymbolRef() + val name = readNameRef() + val body = readTreeRef() + (Bind(name, body). + setSymbol(symbol). + setType(tpe)) + + case UNAPPLYtree => + val fun = readTreeRef() + val args = until(end, readTreeRef) (UnApply(fun: Tree, args).setType(tpe)) - case ARRAYVALUEtree => - val elemtpt = readTreeRef() - val trees = until(end, readTreeRef) - (ArrayValue(elemtpt, trees).setType(tpe)) + case ARRAYVALUEtree => + val elemtpt = readTreeRef() + val trees = until(end, readTreeRef) + (ArrayValue(elemtpt, trees).setType(tpe)) - case FUNCTIONtree => - val symbol = readSymbolRef() - val body = readTreeRef() - val vparams = until(end, readValDefRef) - (Function(vparams, body). - setSymbol(symbol). - setType(tpe)) + case FUNCTIONtree => + val symbol = readSymbolRef() + val body = readTreeRef() + val vparams = until(end, readValDefRef) + (Function(vparams, body). + setSymbol(symbol). + setType(tpe)) - case ASSIGNtree => + case ASSIGNtree => val lhs = readTreeRef() val rhs = readTreeRef() - Assign(lhs, rhs).setType(tpe) + Assign(lhs, rhs).setType(tpe) - case IFtree => + case IFtree => val cond = readTreeRef() val thenp = readTreeRef() val elsep = readTreeRef() - If(cond, thenp, elsep).setType(tpe) + If(cond, thenp, elsep).setType(tpe) - case MATCHtree => + case MATCHtree => val selector = readTreeRef() val cases = until(end, readCaseDefRef) - Match(selector, cases).setType(tpe) + Match(selector, cases).setType(tpe) - case RETURNtree => - val symbol = readSymbolRef() - val expr = readTreeRef() - (Return(expr). - setSymbol(symbol). - setType(tpe)) + case RETURNtree => + val symbol = readSymbolRef() + val expr = readTreeRef() + (Return(expr). + setSymbol(symbol). + setType(tpe)) - case TREtree => + case TREtree => val block = readTreeRef() - val finalizer = readTreeRef() - val catches = until(end, readCaseDefRef) - Try(block, catches, finalizer).setType(tpe) + val finalizer = readTreeRef() + val catches = until(end, readCaseDefRef) + Try(block, catches, finalizer).setType(tpe) - case THROWtree => - val expr = readTreeRef() - Throw(expr).setType(tpe) + case THROWtree => + val expr = readTreeRef() + Throw(expr).setType(tpe) - case NEWtree => - val tpt = readTreeRef() - New(tpt).setType(tpe) + case NEWtree => + val tpt = readTreeRef() + New(tpt).setType(tpe) - case TYPEDtree => - val expr = readTreeRef() - val tpt = readTreeRef() + case TYPEDtree => + val expr = readTreeRef() + val tpt = readTreeRef() Typed(expr, tpt).setType(tpe) - case TYPEAPPLYtree => - val fun = readTreeRef() - val args = until(end, readTreeRef) - TypeApply(fun, args).setType(tpe) - - case APPLYtree => - val fun = readTreeRef() + case TYPEAPPLYtree => + val fun = readTreeRef() val args = until(end, readTreeRef) - Apply(fun, args).setType(tpe) + TypeApply(fun, args).setType(tpe) + case APPLYtree => + val fun = readTreeRef() + val args = until(end, readTreeRef) + if (fun.symbol hasFlag OVERLOADED) { + fun.setType(fun.symbol.info) + typer.infer.inferMethodAlternative(fun, Nil, args map (_.tpe), tpe) + } + Apply(fun, args).setType(tpe) - case APPLYDYNAMICtree => - val symbol = readSymbolRef() - val qual = readTreeRef() + case APPLYDYNAMICtree => + val symbol = readSymbolRef() + val qual = readTreeRef() val args = until(end, readTreeRef) - ApplyDynamic(qual, args).setSymbol(symbol).setType(tpe) + ApplyDynamic(qual, args).setSymbol(symbol).setType(tpe) - case SUPERtree => - val symbol = readSymbolRef() - val qual = readNameRef() - val mix = readNameRef() - Super(qual, mix).setSymbol(symbol).setType(tpe) + case SUPERtree => + val symbol = readSymbolRef() + val qual = readNameRef() + val mix = readNameRef() + Super(qual, mix).setSymbol(symbol).setType(tpe) case THIStree => - val symbol = readSymbolRef() - val qual = readNameRef() - This(qual).setSymbol(symbol).setType(tpe) + val symbol = readSymbolRef() + val qual = readNameRef() + This(qual).setSymbol(symbol).setType(tpe) case SELECTtree => - val symbol = readSymbolRef() - val qualifier = readTreeRef() - val selector = readNameRef() - Select(qualifier, selector).setSymbol(symbol).setType(tpe) + val symbol = readSymbolRef() + val qualifier = readTreeRef() + val selector = readNameRef() + Select(qualifier, selector).setSymbol(symbol).setType(tpe) - case IDENTtree => - val symbol = readSymbolRef() - val name = readNameRef() - Ident(name).setSymbol(symbol).setType(tpe) + case IDENTtree => + val symbol = readSymbolRef() + val name = readNameRef() + Ident(name).setSymbol(symbol).setType(tpe) - case LITERALtree => - val value = readConstantRef() - Literal(value).setType(tpe) + case LITERALtree => + val value = readConstantRef() + Literal(value).setType(tpe) - case TYPEtree => - TypeTree().setType(tpe) + case TYPEtree => + TypeTree().setType(tpe) - case ANNOTATEDtree => - val annot = readAnnotationTreeRef() + case ANNOTATEDtree => + val annot = readTreeRef() val arg = readTreeRef() - Annotated(annot, arg).setType(tpe) + Annotated(annot, arg).setType(tpe) - case SINGLETONTYPEtree => - val ref = readTreeRef() - SingletonTypeTree(ref).setType(tpe) + case SINGLETONTYPEtree => + val ref = readTreeRef() + SingletonTypeTree(ref).setType(tpe) - case SELECTFROMTYPEtree => + case SELECTFROMTYPEtree => val qualifier = readTreeRef() val selector = readNameRef() - SelectFromTypeTree(qualifier, selector).setType(tpe) + SelectFromTypeTree(qualifier, selector).setType(tpe) - case COMPOUNDTYPEtree => - val templ = readTemplateRef() - CompoundTypeTree(templ: Template).setType(tpe) + case COMPOUNDTYPEtree => + val templ = readTemplateRef() + CompoundTypeTree(templ: Template).setType(tpe) - case APPLIEDTYPEtree => - val tpt = readTreeRef() + case APPLIEDTYPEtree => + val tpt = readTreeRef() val args = until(end, readTreeRef) - AppliedTypeTree(tpt, args).setType(tpe) + AppliedTypeTree(tpt, args).setType(tpe) - case TYPEBOUNDStree => - val lo = readTreeRef() - val hi = readTreeRef() - TypeBoundsTree(lo, hi).setType(tpe) + case TYPEBOUNDStree => + val lo = readTreeRef() + val hi = readTreeRef() + TypeBoundsTree(lo, hi).setType(tpe) - case EXISTENTIALTYPEtree => - val tpt = readTreeRef() - val whereClauses = until(end, readTreeRef) - ExistentialTypeTree(tpt, whereClauses).setType(tpe) + case EXISTENTIALTYPEtree => + val tpt = readTreeRef() + val whereClauses = until(end, readTreeRef) + ExistentialTypeTree(tpt, whereClauses).setType(tpe) - case _ => + case _ => errorBadSignature("unknown tree type (" + tag + ")") } } @@ -743,15 +836,15 @@ abstract class UnPickler { def readModifiers(): Modifiers = { val tag = readNat() if (tag != MODIFIERS) - errorBadSignature("expected a modifiers tag (" + tag + ")") + errorBadSignature("expected a modifiers tag (" + tag + ")") val end = readNat() + readIndex val pflagsHi = readNat() val pflagsLo = readNat() val pflags = (pflagsHi.toLong << 32) + pflagsLo val flags = pickledToRawFlags(pflags) val privateWithin = readNameRef() - val annotations = until(end, readAnnotationTreeRef) - Modifiers(flags, privateWithin, annotations) + val annotations = until(end, () => at(readNat(), () => readTree(true))) // @LUC TODO remove this line + Modifiers(flags, privateWithin, Nil) } /* Read a reference to a pickled item */ @@ -761,10 +854,10 @@ abstract class UnPickler { private def readConstantRef(): Constant = at(readNat(), readConstant) private def readAnnotationArgRef(): AnnotationArgument = at(readNat(), readAnnotationArg) - private def readTreeAttribRef(): AnnotationInfo = - at(readNat(), readTreeAttrib) - private def readAnnotationTreeRef(): Annotation = - at(readNat(), readAnnotationTree) + private def readConstantAnnotationArgRef(): ConstantAnnotationArgument = + at(readNat(), readConstantAnnotationArg) + private def readAnnotationRef(): AnnotationInfo = + at(readNat(), readAnnotation) private def readModifiersRef(): Modifiers = at(readNat(), readModifiers) private def readTreeRef(): Tree = @@ -772,32 +865,32 @@ abstract class UnPickler { private def readTemplateRef(): Template = readTreeRef() match { - case templ:Template => templ - case other => + case templ:Template => templ + case other => errorBadSignature("expected a template (" + other + ")") } private def readCaseDefRef(): CaseDef = readTreeRef() match { - case tree:CaseDef => tree - case other => + case tree:CaseDef => tree + case other => errorBadSignature("expected a case def (" + other + ")") } private def readValDefRef(): ValDef = readTreeRef() match { - case tree:ValDef => tree - case other => + case tree:ValDef => tree + case other => errorBadSignature("expected a ValDef (" + other + ")") } private def readIdentRef(): Ident = readTreeRef() match { - case tree:Ident => tree - case other => + case tree:Ident => tree + case other => errorBadSignature("expected an Ident (" + other + ")") } private def readTypeDefRef(): TypeDef = readTreeRef() match { - case tree:TypeDef => tree - case other => + case tree:TypeDef => tree + case other => errorBadSignature("expected an TypeDef (" + other + ")") } @@ -805,12 +898,13 @@ abstract class UnPickler { private def errorBadSignature(msg: String) = throw new RuntimeException("malformed Scala signature of " + classRoot.name + " at " + readIndex + "; " + msg) + /** @LUC TODO Warning about reflection trees in pickle. Remove for 2.8.0 */ private var printedReflectAnnotationWarning = false private def reflectAnnotationWarning() { if (!printedReflectAnnotationWarning) { - global.warning( - "warning: dropping a legacy format annotation in " + classRoot.name) - printedReflectAnnotationWarning = true + global.warning( + "warning: dropping a legacy format annotation in " + classRoot.name) + printedReflectAnnotationWarning = true } } diff --git a/src/compiler/scala/tools/nsc/transform/CleanUp.scala b/src/compiler/scala/tools/nsc/transform/CleanUp.scala index fd3257333c..6a0d0e1f8b 100644 --- a/src/compiler/scala/tools/nsc/transform/CleanUp.scala +++ b/src/compiler/scala/tools/nsc/transform/CleanUp.scala @@ -742,9 +742,9 @@ abstract class CleanUp extends Transform { if (settings.target.value == "jvm-1.5") { val sym = cdef.symbol // is this an anonymous function class? - if (sym.isAnonymousFunction && !sym.hasAttribute(SerializableAttr)) - sym.attributes = - AnnotationInfo(definitions.SerializableAttr.tpe, List(), List()) :: sym.attributes + if (sym.isAnonymousFunction && !sym.hasAnnotation(SerializableAttr)) + sym.addAnnotation( + AnnotationInfo(definitions.SerializableAttr.tpe, List(), List())) } super.transform(tree) diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index a4125dfa2a..402df5c48d 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -457,8 +457,8 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter var checkExhaustive = true var requireSwitch = false - def isUncheckedAnnotation(tpe: Type) = tpe hasAttribute UncheckedClass - def isSwitchAnnotation(tpe: Type) = tpe hasAttribute SwitchClass + def isUncheckedAnnotation(tpe: Type) = tpe hasAnnotation UncheckedClass + def isSwitchAnnotation(tpe: Type) = tpe hasAnnotation SwitchClass nselector match { case Typed(nselector1, tpt) => diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 4a13690efd..3dc9588208 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -284,7 +284,7 @@ abstract class Mixin extends InfoTransform { setFlag (LOCAL | PRIVATE | member.getFlag(MUTABLE | LAZY)) setFlag (if (!member.hasFlag(STABLE)) MUTABLE else 0) setInfo member.tpe.resultType - setAttributes member.attributes) + setAnnotations member.annotations) } } } else if (member hasFlag SUPERACCESSOR) { // mixin super accessors @@ -565,7 +565,7 @@ abstract class Mixin extends InfoTransform { .setInfo(definitions.IntClass.tpe) .setFlag(PROTECTED) atPhase(currentRun.typerPhase) { - sym.attributes = AnnotationInfo(definitions.VolatileAttr.tpe, List(), List()) :: sym.attributes + sym.addAnnotation(AnnotationInfo(definitions.VolatileAttr.tpe, List(), List())) } clazz.info.decls.enter(sym) addDef(clazz.pos, ValDef(sym, Literal(Constant(0)))) diff --git a/src/compiler/scala/tools/nsc/transform/Reifiers.scala b/src/compiler/scala/tools/nsc/transform/Reifiers.scala index 300649aa4d..37a0ebcc1b 100644 --- a/src/compiler/scala/tools/nsc/transform/Reifiers.scala +++ b/src/compiler/scala/tools/nsc/transform/Reifiers.scala @@ -86,7 +86,7 @@ trait Reifiers { boundss, reify(result)) //todo: treat ExistentialType - case AnnotatedType(attribs, tp, _) => + case AnnotatedType(annots, tp, _) => reify(tp) case _ => println("could not reify: " + tp) diff --git a/src/compiler/scala/tools/nsc/transform/TailCalls.scala b/src/compiler/scala/tools/nsc/transform/TailCalls.scala index af6c65ece2..56f4cce69f 100644 --- a/src/compiler/scala/tools/nsc/transform/TailCalls.scala +++ b/src/compiler/scala/tools/nsc/transform/TailCalls.scala @@ -39,7 +39,7 @@ abstract class TailCalls extends Transform } /** The @tailrec annotation indicates TCO is mandatory */ - private def tailrecRequired(defdef: DefDef) = defdef.symbol hasAttribute TailrecClass + private def tailrecRequired(defdef: DefDef) = defdef.symbol hasAnnotation TailrecClass /** * A Tail Call Transformer diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 15684c23d4..6aa98bb6e9 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -326,7 +326,7 @@ abstract class UnCurry extends InfoTransform with TypingTransformers { case Match(selector, cases) => atPos(tree.pos) { Match( - Annotated(Annotation(New(TypeTree(UncheckedClass.tpe), List(List())), List()), selector), + Annotated(New(TypeTree(UncheckedClass.tpe), List(List())), selector), cases) } case _ => diff --git a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala index ed1c35c1f1..c393617288 100644 --- a/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala +++ b/src/compiler/scala/tools/nsc/typechecker/DeVirtualize.scala @@ -241,7 +241,7 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers { protected def mkAbstractType(clazz: Symbol): Symbol = { val cabstype = clazz.owner.newAbstractType(clazz.pos, clazz.name) .setFlag(clazz.flags & absTypeFlagMask | SYNTHETIC) - .setAttributes(clazz.attributes) + .setAnnotations(clazz.annotations) atPhase(ownPhase.next) { cabstype setInfo new PolyTypeCompleter(cabstype, clazz) { def getInfo = { @@ -291,7 +291,7 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers { val pos = if (clazz.owner == owner) clazz.pos else owner.pos val factory = owner.newMethod(pos, factoryName(clazz)) .setFlag(clazz.flags & factoryFlagMask | SYNTHETIC) - .setAttributes(clazz.attributes) + .setAnnotations(clazz.annotations) factory setInfo new PolyTypeCompleter(factory, clazz) { private def copyType(tpe: Type): Type = tpe match { case MethodType(formals, restpe) => MethodType(formals, copyType(restpe)) @@ -316,7 +316,7 @@ abstract class DeVirtualize extends InfoTransform with TypingTransformers { protected def mkConcreteClass(clazz: Symbol, factory: Symbol) = { val cclazz = factory.newClass(clazz.pos, concreteClassName(clazz)) .setFlag(FINAL | SYNTHETIC) - .setAttributes(clazz.attributes) + .setAnnotations(clazz.annotations) cclazz setInfo new LazyType { override def complete(sym: Symbol) { diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index b41aff1155..74a0a6c464 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -179,7 +179,7 @@ self: Analyzer => private def dominates(dtor: Type, dted: Type): Boolean = { def core(tp: Type): Type = tp.normalize match { case RefinedType(parents, defs) => intersectionType(parents map core, tp.typeSymbol.owner) - case AnnotatedType(attribs, tp, selfsym) => core(tp) + case AnnotatedType(annots, tp, selfsym) => core(tp) case ExistentialType(tparams, result) => core(result).subst(tparams, tparams map (t => core(t.info.bounds.hi))) case PolyType(tparams, result) => core(result).subst(tparams, tparams map (t => core(t.info.bounds.hi))) case _ => tp diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index d9dc0969f4..ef2fa32118 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -356,7 +356,7 @@ trait Namers { self: Analyzer => loaders.openPackageModule(tree.symbol) } - case ValDef(mods, name, tp, rhs) => + case vd @ ValDef(mods, name, tp, rhs) => if ((!context.owner.isClass || (mods.flags & (PRIVATE | LOCAL)) == (PRIVATE | LOCAL) || name.endsWith(nme.OUTER, nme.OUTER.length) || @@ -375,23 +375,27 @@ trait Namers { self: Analyzer => var getter = owner.newMethod(tree.pos, name).setFlag(accflags) setPrivateWithin(tree, getter, mods) getter = enterInScope(getter).asInstanceOf[TermSymbol] - setInfo(getter)(namerOf(getter).getterTypeCompleter(tree)) + // needs the current context for adding synthetic BeanGetter / -Setter. + // namerOf(getter) has a primaryConstructorContext which cannot be used + // do add definitions to the class + setInfo(getter)(namerOf(getter).getterTypeCompleter(vd, context)) if ((mods.flags & MUTABLE) != 0) { var setter = owner.newMethod(tree.pos, nme.getterToSetter(name)) .setFlag(accflags & ~STABLE & ~CASEACCESSOR) setPrivateWithin(tree, setter, mods) setter = enterInScope(setter).asInstanceOf[TermSymbol] - setInfo(setter)(namerOf(setter).setterTypeCompleter(tree)) + setInfo(setter)(namerOf(setter).setterTypeCompleter(vd)) } tree.symbol = - if ((mods.flags & DEFERRED) == 0) { + if (!mods.hasFlag(DEFERRED)) { var vsym = if (!context.owner.isClass) { assert((mods.flags & LAZY) != 0) // if not a field, it has to be a lazy val owner.newValue(tree.pos, name + "$lzy" ).setFlag(mods.flags | MUTABLE) } else { owner.newValue(tree.pos, nme.getterToLocal(name)) - .setFlag(mods.flags & FieldFlags | PRIVATE | LOCAL | (if ((mods.flags & LAZY) != 0) MUTABLE else 0)) + .setFlag(mods.flags & FieldFlags | PRIVATE | LOCAL | + (if (mods.hasFlag(LAZY)) MUTABLE else 0)) } vsym = enterInScope(vsym).asInstanceOf[TermSymbol] setInfo(vsym)(namerOf(vsym).typeCompleter(tree)) @@ -474,21 +478,74 @@ trait Namers { self: Analyzer => } } - def getterTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym => + def getterTypeCompleter(vd: ValDef, getterCtx: Context) = mkTypeCompleter(vd) { sym => if (settings.debug.value) log("defining " + sym) - sym.setInfo(PolyType(List(), typeSig(tree))) + val tp = typeSig(vd) + sym.setInfo(PolyType(List(), tp)) + if (sym.hasAnnotation(BeanPropertyAttr) && sym.owner.isClass && !forMSIL) + addBeanGetterSetter(vd, tp, getterCtx) if (settings.debug.value) log("defined " + sym) validate(sym) } - def setterTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym => + def setterTypeCompleter(vd: ValDef) = mkTypeCompleter(vd) { sym => if (settings.debug.value) log("defining " + sym) - val param = sym.newSyntheticValueParam(typeSig(tree)) + val param = sym.newSyntheticValueParam(typeSig(vd)) sym.setInfo(MethodType(List(param), UnitClass.tpe)) if (settings.debug.value) log("defined " + sym) validate(sym) } + private def addBeanGetterSetter(vd: ValDef, tp: Type, getterCtx: Context) { + val ValDef(mods, name, _, _) = vd + val sym = vd.symbol + if (!name(0).isLetter) + context.error(sym.pos, "`BeanProperty' annotation can be applied "+ + "only to fields that start with a letter") + else { + val tmplCtx = getterCtx.nextEnclosing(c => c.scope.toList.contains(sym)) + assert(tmplCtx != NoContext, context) + val tmplNamer = newNamer(tmplCtx) + val flags = (mods.flags & (DEFERRED | OVERRIDE | STATIC)) | SYNTHETIC + val beanName = name(0).toString.toUpperCase + name.subName(1, name.length) + val getterName = if (tp == BooleanClass.tpe) "is" + beanName + else "get" + beanName + val existingGetter = sym.owner.info.decl(getterName) + if (existingGetter != NoSymbol) { + if (!existingGetter.hasFlag(SYNTHETIC)) + context.error(sym.pos, "a defintion of `"+ getterName + + "' already exists in "+ sym.owner) + } else { + val getterMods = Modifiers(flags, mods.privateWithin, + mods.annotations map (_.duplicate)) + val beanGetterDef = atPos(sym.pos) { + DefDef(getterMods, getterName, Nil, List(Nil), TypeTree(tp), + if (mods hasFlag DEFERRED) EmptyTree + else Select(This(sym.owner.name), name)) } + tmplNamer.enterSyntheticSym(beanGetterDef) + } + if (mods hasFlag MUTABLE) { + val setterName = "set" + beanName + val existingSetter = sym.owner.info.decl(setterName) + if (existingSetter != NoSymbol) { + if (!existingSetter.hasFlag(SYNTHETIC)) + context.error(sym.pos, "a defintion of `"+ setterName + + "' already exists in "+ sym.owner) + } else { + val setterMods = Modifiers(flags, mods.privateWithin, + mods.annotations map (_.duplicate)) + val param = ValDef(NoMods, "new" + name, TypeTree(tp), EmptyTree) + val beanSetterDef = atPos(sym.pos) { + DefDef(setterMods, setterName, Nil, List(List(param)), + TypeTree(UnitClass.tpe), + if (mods hasFlag DEFERRED) EmptyTree + else Assign(Select(This(sym.owner.name), name), Ident(param.name))) } + tmplNamer.enterSyntheticSym(beanSetterDef) + } + } + } + } + def selfTypeCompleter(tree: Tree) = mkTypeCompleter(tree) { sym => var selftpe = typer.typedType(tree).tpe if (!(selftpe.typeSymbol isNonBottomSubClass sym.owner)) @@ -1002,18 +1059,16 @@ trait Namers { self: Analyzer => def typeSig(tree: Tree): Type = { val sym: Symbol = tree.symbol // For definitions, transform Annotation trees to AnnotationInfos, assign - // them to the sym's attributes. Type annotations: see Typer.typedAnnotated - tree match { + // them to the sym's annotations. Type annotations: see Typer.typedAnnotated + val annotated = if (sym.isModule) sym.moduleClass else sym + if (annotated.annotations.isEmpty) tree match { case defn: MemberDef => - val ainfos = for { - annot <- defn.mods.annotations - val ainfo = typer.typedAnnotation(annot, tree.symbol) - if !ainfo.atp.isError && annot != null - } yield ainfo - if (!ainfos.isEmpty) { - val annotated = if (sym.isModule) sym.moduleClass else sym - annotated.attributes = ainfos + val ainfos = defn.mods.annotations filter { _ != null } map { ann => + // need to be lazy, #1782 + LazyAnnotationInfo(() => typer.typedAnnotation(ann)) } + if (!ainfos.isEmpty) + annotated.setAnnotations(ainfos) case _ => } implicit val scopeKind = TypeSigScopeKind @@ -1032,7 +1087,7 @@ trait Namers { self: Analyzer => case DefDef(mods, _, tparams, vparamss, tpt, rhs) => newNamer(context.makeNewScope(tree, sym)).methodSig(mods, tparams, vparamss, tpt, rhs) - case vdef @ ValDef(mods, _, tpt, rhs) => + case vdef @ ValDef(mods, name, tpt, rhs) => val typer1 = typer.constrTyperIf(sym.hasFlag(PARAM | PRESUPER) && sym.owner.isConstructor) if (tpt.isEmpty) { if (rhs.isEmpty) { @@ -1161,7 +1216,7 @@ trait Namers { self: Analyzer => sym.isValueParameter && sym.owner.isClass && sym.owner.hasFlag(CASE)) context.error(sym.pos, "pass-by-name arguments not allowed for case class parameters"); if (sym hasFlag DEFERRED) { // virtual classes count, too - if (sym.hasAttribute(definitions.NativeAttr)) + if (sym.hasAnnotation(definitions.NativeAttr)) sym.resetFlag(DEFERRED) else if (!sym.isValueParameter && !sym.isTypeParameterOrSkolem && !context.tree.isInstanceOf[ExistentialTypeTree] && diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 0403e50dcd..c11b157208 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -780,7 +780,11 @@ abstract class RefChecks extends InfoTransform { */ def checkDeprecated(sym: Symbol, pos: Position) { if (sym.isDeprecated && !currentOwner.ownerChain.exists(_.isDeprecated)) { - unit.deprecationWarning(pos, sym+sym.locationString+" is deprecated") + val dmsg = sym.deprecationMessage + val msg = sym.toString + sym.locationString +" is deprecated"+ + (if (dmsg.isDefined) ": "+ dmsg.get + else "") + unit.deprecationWarning(pos, msg) } } @@ -836,18 +840,24 @@ abstract class RefChecks extends InfoTransform { } traverse tree.tpe } - // if this tree can carry modifiers, make sure any annotations also conform to type bounds; bug #935 + // Apply RefChecks to annotations. Makes sure the annotations conform to + // type bounds (bug #935), issues deprecation warnings for symbols used + // inside annotations. tree match { - case x: MemberDef => checkAnnotations(x.mods.annotations.map(a => (a.tpe, a.pos))) - case TypeTree() => doTypeTraversal { - case AnnotatedType(attribs, _, _) => checkAnnotations(attribs.map(a => (a.atp, tree.pos))) + case m: MemberDef => + checkAnnotations(m.symbol.annotations.map(a => (a.atp, tree.pos))) + transformTrees(m.symbol.annotations.flatMap(a => a.args.map(_.intTree))) + case TypeTree() => doTypeTraversal { + case AnnotatedType(annots, _, _) => + checkAnnotations(annots.map(a => (a.atp, tree.pos))) + transformTrees(annots.flatMap(a => a.args.map(_.intTree))) case _ => } - case _ => + case _ => } tree match { - case DefDef(mods, name, tparams, vparams, tpt, EmptyTree) if tree.symbol.hasAttribute(definitions.NativeAttr) => + case DefDef(mods, name, tparams, vparams, tpt, EmptyTree) if tree.symbol.hasAnnotation(definitions.NativeAttr) => tree.symbol.resetFlag(DEFERRED) result = transform(treeCopy.DefDef(tree, mods, name, tparams, vparams, tpt, typed(Apply(gen.mkAttributedRef(definitions.Predef_error), List(Literal("native method stub")))))) diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index eae6eedc00..a2d2b0a433 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -210,7 +210,7 @@ trait SyntheticMethods { self: Analyzer => } def hasSerializableAnnotation(clazz: Symbol): Boolean = - !clazz.getAttributes(definitions.SerializableAttr).isEmpty + clazz.hasAnnotation(definitions.SerializableAttr) def readResolveMethod: Tree = { // !!! the synthetic method "readResolve" should be private, @@ -231,52 +231,8 @@ trait SyntheticMethods { self: Analyzer => result } - def beanSetterOrGetter(sym: Symbol): Symbol = - if (!sym.name(0).isLetter) { - context.unit.error(sym.pos, "attribute `BeanProperty' can be applied only to fields that start with a letter") - NoSymbol - } else { - var name0 = sym.name - if (sym.isSetter) name0 = nme.setterToGetter(name0) - val prefix = if (sym.isSetter) "set" else - if (sym.tpe.resultType == BooleanClass.tpe) "is" else "get" - val arity = if (sym.isSetter) 1 else 0 - val name1 = prefix + name0(0).toUpperCase + name0.subName(1, name0.length) - val sym1 = clazz.info.decl(name1) - if (sym1 != NoSymbol && sym1.tpe.paramTypes.length == arity) { - context.unit.error(sym.pos, "a definition of `"+name1+"' already exists in " + clazz) - NoSymbol - } else { - val m = clazz.newMethod(sym.pos, name1) - m.setInfo(sym.info.cloneInfo(clazz)) - .setFlag(sym.getFlag(DEFERRED | OVERRIDE | STATIC)) - m - } - } - val ts = new ListBuffer[Tree] - def addBeanGetterMethod(sym: Symbol) = { - val getter = beanSetterOrGetter(sym) - if (getter != NoSymbol) { - clazz.info.decls.enter(getter) - ts += typer.typed(DefDef( - getter, - if (sym hasFlag DEFERRED) EmptyTree else gen.mkAttributedRef(sym))) - } - } - - def addBeanSetterMethod(sym: Symbol) = { - val setter = beanSetterOrGetter(sym) - if (setter != NoSymbol) { - clazz.info.decls.enter(setter) - ts += typer.typed(DefDef( - setter, - if (sym hasFlag DEFERRED) EmptyTree - else Apply(gen.mkAttributedRef(sym), List(Ident(setter.paramss.head.head))))) - } - } - def isPublic(sym: Symbol) = !sym.hasFlag(PRIVATE | PROTECTED) && sym.privateWithin == NoSymbol @@ -285,7 +241,7 @@ trait SyntheticMethods { self: Analyzer => if (clazz hasFlag CASE) { val isTop = !(clazz.info.baseClasses.tail exists (_ hasFlag CASE)) // case classes are implicitly declared serializable - clazz.attributes = AnnotationInfo(SerializableAttr.tpe, List(), List()) :: clazz.attributes + clazz.addAnnotation(AnnotationInfo(SerializableAttr.tpe, List(), List())) if (isTop) { for (stat <- templ.body) { @@ -324,15 +280,6 @@ trait SyntheticMethods { self: Analyzer => // only for those that carry a @serializable annotation? if (!hasImplementation(nme.readResolve)) ts += readResolveMethod } - if (!forMSIL) - for (sym <- clazz.info.decls.toList) - if (!sym.getAttributes(BeanPropertyAttr).isEmpty) - if (sym.isGetter) - addBeanGetterMethod(sym) - else if (sym.isSetter) - addBeanSetterMethod(sym) - else if (sym.isMethod || sym.isType) - context.unit.error(sym.pos, "attribute `BeanProperty' is not applicable to " + sym) } catch { case ex: TypeError => if (!reporter.hasErrors) throw ex diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index e6aa3119e1..4e4f75a4cb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -333,7 +333,7 @@ trait Typers { self: Analyzer => def checkNonCyclic(pos: Position, tp: Type): Boolean = { def checkNotLocked(sym: Symbol): Boolean = { sym.initialize - sym.lockOK || {error(pos, "cyclic aliasing or subtyping involving "+sym); false} + sym.lockOK || {error(pos, "cyclic aliasing or subtyping involving "+sym); false} } tp match { case TypeRef(pre, sym, args) => @@ -521,10 +521,10 @@ trait Typers { self: Analyzer => while (c != NoContext && c.owner.name != qual) c = c.outer.enclClass } if (c == NoContext || !(packageOK || c.enclClass.tree.isInstanceOf[Template])) - error( - tree.pos, - if (qual.isEmpty) tree+" can be used only in a class, object, or template" - else qual+" is not an enclosing class") + error( + tree.pos, + if (qual.isEmpty) tree+" can be used only in a class, object, or template" + else qual+" is not an enclosing class") c } @@ -1153,7 +1153,7 @@ trait Typers { self: Analyzer => if (!(selfType <:< parent.tpe.typeOfThis) && !phase.erasedTypes && !(context.owner hasFlag SYNTHETIC) && // don't do this check for synthetic concrete classes for virtuals (part of DEVIRTUALIZE) - !(settings.suppressVTWarn.value)) + !(settings.suppressVTWarn.value)) { //Console.println(context.owner);//DEBUG //Console.println(context.owner.unsafeTypeParams);//DEBUG @@ -1205,8 +1205,8 @@ trait Typers { self: Analyzer => */ def typedClassDef(cdef: ClassDef): Tree = { // attributes(cdef) - val typedMods = typedModifiers(cdef.mods) - val clazz = cdef.symbol; + val clazz = cdef.symbol + val typedMods = removeAnnotations(cdef.mods) assert(clazz != NoSymbol) reenterTypeParams(cdef.tparams) val tparams1 = List.mapConserve(cdef.tparams)(typedTypeDef) @@ -1214,11 +1214,11 @@ trait Typers { self: Analyzer => .typedTemplate(cdef.impl, parentTypes(cdef.impl)) val impl2 = addSyntheticMethods(impl1, clazz, context) if ((clazz != ClassfileAnnotationClass) && - (clazz isNonBottomSubClass ClassfileAnnotationClass)) - unit.warning (cdef.pos, + (clazz isNonBottomSubClass ClassfileAnnotationClass)) + unit.warning (cdef.pos, "implementation restriction: subclassing Classfile does not\n"+ "make your annotation visible at runtime. If that is what\n"+ - "you want, you must write the annotation class in Java.") + "you want, you must write the annotation class in Java.") treeCopy.ClassDef(cdef, typedMods, cdef.name, tparams1, impl2) .setType(NoType) } @@ -1230,8 +1230,8 @@ trait Typers { self: Analyzer => def typedModuleDef(mdef: ModuleDef): Tree = { //Console.println("sourcefile of " + mdef.symbol + "=" + mdef.symbol.sourceFile) // attributes(mdef) - val typedMods = typedModifiers(mdef.mods) val clazz = mdef.symbol.moduleClass + val typedMods = removeAnnotations(mdef.mods) assert(clazz != NoSymbol) val impl1 = newTyper(context.make(mdef.impl, clazz, scopeFor(mdef.impl, TypedDefScopeKind))) .typedTemplate(mdef.impl, parentTypes(mdef.impl)) @@ -1247,44 +1247,47 @@ trait Typers { self: Analyzer => def addGetterSetter(stat: Tree): List[Tree] = stat match { case ValDef(mods, name, tpt, rhs) if (mods.flags & (PRIVATE | LOCAL)) != (PRIVATE | LOCAL) - && !stat.symbol.isModuleVar - && !stat.symbol.hasFlag(LAZY) => - val vdef = treeCopy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpt, rhs) - val value = vdef.symbol + && !stat.symbol.isModuleVar => + val value = stat.symbol val getter = if ((mods hasFlag DEFERRED)) value else value.getter(value.owner) assert(getter != NoSymbol, stat) if (getter hasFlag OVERLOADED) error(getter.pos, getter+" is defined twice") - val getterDef: DefDef = atPos(vdef) { - getter.attributes = value.initialize.attributes - val result = DefDef(getter, - if (mods hasFlag DEFERRED) EmptyTree - else typed( - atPos(vdef) { gen.mkCheckInit(Select(This(value.owner), value)) }, - EXPRmode, value.tpe)) - result.tpt.asInstanceOf[TypeTree] setOriginal tpt /* setPos tpt.pos */ - checkNoEscaping.privates(getter, result.tpt) - treeCopy.DefDef(result, result.mods withAnnotations mods.annotations, result.name, - result.tparams, result.vparamss, result.tpt, result.rhs) - //todo: withAnnotations is probably unnecessary - } - def setterDef: DefDef = { - val setr = getter.setter(value.owner) - setr.attributes = value.attributes - val result = atPos(vdef)( - DefDef(setr, - if ((mods hasFlag DEFERRED) || (setr hasFlag OVERLOADED)) - EmptyTree - else - typed(Assign(Select(This(value.owner), value), - Ident(setr.paramss.head.head))))) - treeCopy.DefDef(result, result.mods withAnnotations mods.annotations, result.name, - result.tparams, result.vparamss, result.tpt, result.rhs) - } - val gs = if (mods hasFlag MUTABLE) List(getterDef, setterDef) - else List(getterDef) - if (mods hasFlag DEFERRED) gs else vdef :: gs + // todo: potentially dangerous not to duplicate the trees and clone the symbols / types. + getter.setAnnotations(value.initialize.annotations) + + if (value.hasFlag(LAZY)) List(stat) + else { + val vdef = treeCopy.ValDef(stat, mods | PRIVATE | LOCAL, nme.getterToLocal(name), tpt, rhs) + val getterDef: DefDef = atPos(vdef) { + val result = DefDef(getter, + if (mods hasFlag DEFERRED) EmptyTree + else typed( + atPos(vdef) { gen.mkCheckInit(Select(This(value.owner), value)) }, + EXPRmode, value.tpe)) + result.tpt.asInstanceOf[TypeTree] setOriginal tpt /* setPos tpt.pos */ + checkNoEscaping.privates(getter, result.tpt) + treeCopy.DefDef(result, result.mods, result.name, + result.tparams, result.vparamss, result.tpt, result.rhs) + } + def setterDef: DefDef = { + val setr = getter.setter(value.owner) + setr.setAnnotations(value.annotations) + val result = atPos(vdef)( + DefDef(setr, + if ((mods hasFlag DEFERRED) || (setr hasFlag OVERLOADED)) + EmptyTree + else + typed(Assign(Select(This(value.owner), value), + Ident(setr.paramss.head.head))))) + treeCopy.DefDef(result, result.mods, result.name, result.tparams, + result.vparamss, result.tpt, result.rhs) + } + val gs = if (mods hasFlag MUTABLE) List(getterDef, setterDef) + else List(getterDef) + if (mods hasFlag DEFERRED) gs else vdef :: gs + } case DocDef(comment, defn) => addGetterSetter(defn) map (stat => DocDef(comment, stat)) @@ -1342,12 +1345,11 @@ trait Typers { self: Analyzer => treeCopy.Template(templ, parents1, self1, body1) setType clazz.tpe } - /** Type check the annotations within a set of modifiers. */ - def typedModifiers(mods: Modifiers): Modifiers = { - val Modifiers(flags, privateWithin, annotations) = mods - val typedAnnots = annotations.map(typed(_).asInstanceOf[Annotation]) - Modifiers(flags, privateWithin, typedAnnots) - } + /** Remove definition annotations from modifiers (they have been saved + * into the symbol's ``annotations'' in the type completer / namer) + */ + def removeAnnotations(mods: Modifiers): Modifiers = + Modifiers(mods.flags, mods.privateWithin, Nil) /** * @param vdef ... @@ -1357,7 +1359,7 @@ trait Typers { self: Analyzer => // attributes(vdef) val sym = vdef.symbol val typer1 = constrTyperIf(sym.hasFlag(PARAM) && sym.owner.isConstructor) - val typedMods = typedModifiers(vdef.mods) + val typedMods = removeAnnotations(vdef.mods) var tpt1 = checkNoEscaping.privates(sym, typer1.typedType(vdef.tpt)) checkNonCyclic(vdef, tpt1) @@ -1484,7 +1486,7 @@ trait Typers { self: Analyzer => } checkNonCyclic(ddef, tpt1) ddef.tpt.setType(tpt1.tpe) - val typedMods = typedModifiers(ddef.mods) + val typedMods = removeAnnotations(ddef.mods) var rhs1 = if (ddef.name == nme.CONSTRUCTOR) { if (!meth.isPrimaryConstructor && @@ -1525,7 +1527,7 @@ trait Typers { self: Analyzer => def typedTypeDef(tdef: TypeDef): TypeDef = { reenterTypeParams(tdef.tparams) // @M! val tparams1 = List.mapConserve(tdef.tparams)(typedTypeDef) // @M! - val typedMods = typedModifiers(tdef.mods) + val typedMods = removeAnnotations(tdef.mods) val rhs1 = checkNoEscaping.privates(tdef.symbol, typedType(tdef.rhs)) checkNonCyclic(tdef.symbol) if (tdef.symbol.owner.isType) @@ -2226,112 +2228,205 @@ trait Typers { self: Analyzer => } } - def typedAnnotation(annot: Annotation, owner: Symbol): AnnotationInfo = - typedAnnotation(annot, owner, EXPRmode) + def typedAnnotation(constr: Tree): AnnotationInfo = + typedAnnotation(constr, EXPRmode) - def typedAnnotation(annot: Annotation, owner: Symbol, mode: Int): AnnotationInfo = - typedAnnotation(annot, owner, mode, NoSymbol) + def typedAnnotation(constr: Tree, mode: Int): AnnotationInfo = + typedAnnotation(constr, mode, NoSymbol) - def typedAnnotation(annot: Annotation, owner: Symbol, mode: Int, selfsym: Symbol): AnnotationInfo = { - var attrError: Boolean = false - def error(pos: Position, msg: String): Null = { + def typedAnnotation(constr: Tree, mode: Int, selfsym: Symbol): AnnotationInfo = + typedAnnotation(constr, mode, selfsym, AnnotationClass, false) + + /** + * Convert an annotation constructor call into an AnnotationInfo. + * + * @param annClass the expected annotation class + */ + def typedAnnotation(ann: Tree, mode: Int, selfsym: Symbol, annClass: Symbol, requireJava: Boolean): AnnotationInfo = { + lazy val annotationError = AnnotationInfo(ErrorType, Nil, Nil) + var hasError: Boolean = false + def error(pos: Position, msg: String) = { context.error(pos, msg) - attrError = true - null + hasError = true + annotationError } - def needConst(tr: Tree) { - error(tr.pos, "attribute argument needs to be a constant; found: "+tr) + def needConst(tr: Tree): None.type = { + error(tr.pos, "annotation argument needs to be a constant; found: "+tr) + None } - val typedConstr = - if (selfsym == NoSymbol) { - // why a new typer: definitions inside the annotation's constructor argument - // should not have the annotated's owner as owner. - val typer1 = newTyper(context.makeNewScope(annot.constr, owner)(TypedScopeKind)) - typer1.typed(annot.constr, mode, AnnotationClass.tpe) - } else { - // Since a selfsym is supplied, the annotation should have - // an extra "self" identifier in scope for type checking. - // This is implemented by wrapping the rhs - // in a function like "self => rhs" during type checking, - // and then stripping the "self =>" and substituting - // in the supplied selfsym. - val funcparm = ValDef(NoMods, nme.self, TypeTree(selfsym.info), EmptyTree) - val func = Function(List(funcparm), annot.constr.duplicate) - // The .duplicate of annot.constr - // deals with problems that - // accur if this annotation is - // later typed again, which - // the compiler sometimes does. - // The problem is that "self" - // ident's within annot.constr - // will retain the old symbol - // from the previous typing. - val fun1clazz = FunctionClass(1) - val funcType = typeRef(fun1clazz.tpe.prefix, - fun1clazz, - List(selfsym.info, AnnotationClass.tpe)) + /** Converts an untyped tree to a ConstantAnnotationArgument. If the conversion fails, + * an error message is reporded and None is returned. + */ + def tree2ConstArg(tree: Tree, pt: Type): Option[ConstantAnnotationArgument] = tree match { + case ann @ Apply(Select(New(tpt), nme.CONSTRUCTOR), args) => + val annInfo = typedAnnotation(ann, mode, NoSymbol, pt.typeSymbol, true) + if (annInfo.atp.isErroneous) { + // recursive typedAnnotation call already printed an error, so don't call "error" + hasError = true + None + } else Some(NestedAnnotationArgument(annInfo)) + + // use of: object Array.apply[A <: AnyRef](args: A*): Array[A] = ... + // and object Array.apply(args: Int*): Array[Int] = ... (and similar) + case Apply(fun, members) => + val typedFun = typed(fun, funMode(mode), WildcardType) + if (typedFun.symbol.owner == ArrayModule.moduleClass && + typedFun.symbol.name == nme.apply && + pt.typeSymbol == ArrayClass && + !pt.typeArgs.isEmpty) + trees2ConstArg(members, pt.typeArgs.head) + else + needConst(tree) - typed(func, mode, funcType) match { - case t @ Function(List(arg), rhs) => - val subs = - new TreeSymSubstituter(List(arg.symbol),List(selfsym)) - subs(rhs) - } - } + case Typed(t, _) => tree2ConstArg(t, pt) - lazy val annotationError = AnnotationInfo(ErrorType, Nil, Nil) - typedConstr match { - case t @ Apply(Select(New(tpt), nme.CONSTRUCTOR), args) => - if ((t.tpe==null) || t.tpe.isErroneous) annotationError - else { - val annType = tpt.tpe + case tree => typed(tree, EXPRmode, pt) match { + case l @ Literal(c) if !l.isErroneous => + Some(LiteralAnnotationArgument(c)) + case _ => + needConst(tree) + } + } + def trees2ConstArg(trees: List[Tree], pt: Type): Option[ArrayAnnotationArgument] = { + val args = trees.map(tree2ConstArg(_, pt)) + if (args.exists(_.isEmpty)) None + else Some(ArrayAnnotationArgument(args.map(_.get).toArray)) + } - val needsConstant = - (annType.typeSymbol isNonBottomSubClass ClassfileAnnotationClass) - def annotArg(tree: Tree): AnnotationArgument = { - val arg = new AnnotationArgument(tree) - if (needsConstant && !arg.isConstant) - needConst(tree) - arg - } - val constrArgs = args map annotArg + // begin typedAnnotation + val (fun, argss) = { + def extract(fun: Tree, outerArgss: List[List[Tree]]): + (Tree, List[List[Tree]]) = fun match { + case Apply(f, args) => + extract(f, args :: outerArgss) + case Select(New(tpt), nme.CONSTRUCTOR) => + (fun, outerArgss) + case _ => + error(fun.pos, "unexpected tree in annotationn: "+ fun) + (setError(fun), outerArgss) + } + extract(ann, List()) + } - val attrScope = annType.decls - .filter(sym => sym.isMethod && !sym.isConstructor && sym.hasFlag(JAVA)) + if (fun.isErroneous) annotationError + else { + val typedFun @ Select(New(tpt), _) = typed(fun, funMode(mode), WildcardType) + val annType = tpt.tpe + + if (typedFun.isErroneous) annotationError + else if (annType.typeSymbol isNonBottomSubClass ClassfileAnnotationClass) { + // annotation to be saved as java annotation + val isJava = typedFun.symbol.owner.hasFlag(JAVA) + if (!annType.typeSymbol.isNonBottomSubClass(annClass)) { + error(tpt.pos, "expected annotation of type "+ annClass.tpe +", found "+ annType) + } else if (argss.length > 1) { + error(ann.pos, "multiple argument lists on java annotation") + } else { + val args = + if (argss.head.length == 1 && !isNamed(argss.head.head)) + List(Assign(Ident(nme.value), argss.head.head)) + else argss.head + val annScope = annType.decls + .filter(sym => sym.isMethod && !sym.isConstructor && sym.hasFlag(JAVA)) val names = new collection.mutable.HashSet[Symbol] - names ++= attrScope.iterator.filter(_.isMethod) - if (args.length == 1) { - names.retain(sym => sym.name != nme.value) - } - val nvPairs = annot.elements map { - case vd @ ValDef(_, name, _, rhs) => { - val sym = attrScope.lookupWithContext(name)(context.owner); + names ++= (if (isJava) annScope.iterator + else typedFun.tpe.params.iterator) + val nvPairs = args map { + case arg @ Assign(Ident(name), rhs) => + val sym = if (isJava) annScope.lookupWithContext(name)(context.owner) + else typedFun.tpe.params.find(p => p.name == name).getOrElse(NoSymbol) if (sym == NoSymbol) { - error(vd.pos, "unknown attribute element name: " + name) + error(arg.pos, "unknown annotation argument name: " + name) + (nme.ERROR, None) } else if (!names.contains(sym)) { - error(vd.pos, "duplicate value for element " + name) + error(arg.pos, "duplicate value for anontation argument " + name) + (nme.ERROR, None) } else { names -= sym - val annArg = - annotArg( - typed(rhs, EXPRmode, sym.tpe.resultType)) + val annArg = tree2ConstArg(rhs, sym.tpe.resultType) (sym.name, annArg) } - } + case arg => + error(arg.pos, "java annotation arguments have to be supplied as named arguments") + (nme.ERROR, None) } + for (name <- names) { - if (!name.attributes.contains(AnnotationInfo(AnnotationDefaultAttr.tpe, List(), List()))) { - error(annot.constr.pos, "attribute " + annType.typeSymbol.fullNameString + " is missing element " + name.name) - } + if (!name.annotations.contains(AnnotationInfo(AnnotationDefaultAttr.tpe, List(), List())) && + !name.hasFlag(DEFAULTPARAM)) + error(ann.pos, "annotation " + annType.typeSymbol.fullNameString + " is missing argument " + name.name) + } + + if (hasError) annotationError + else AnnotationInfo(annType, List(), nvPairs map {p => (p._1, p._2.get)}) + } + } else if (requireJava) { + error(ann.pos, "nested java annotations must be defined in java; found: "+ annType) + } else { + val typedAnn = if (selfsym == NoSymbol) { + typed(ann, mode, annClass.tpe) + } else { + // Since a selfsym is supplied, the annotation should have + // an extra "self" identifier in scope for type checking. + // This is implemented by wrapping the rhs + // in a function like "self => rhs" during type checking, + // and then stripping the "self =>" and substituting + // in the supplied selfsym. + val funcparm = ValDef(NoMods, nme.self, TypeTree(selfsym.info), EmptyTree) + val func = Function(List(funcparm), ann.duplicate) + // The .duplicate of annot.constr + // deals with problems that + // accur if this annotation is + // later typed again, which + // the compiler sometimes does. + // The problem is that "self" + // ident's within annot.constr + // will retain the old symbol + // from the previous typing. + val fun1clazz = FunctionClass(1) + val funcType = typeRef(fun1clazz.tpe.prefix, + fun1clazz, + List(selfsym.info, annClass.tpe)) + + typed(func, mode, funcType) match { + case t @ Function(List(arg), rhs) => + val subs = + new TreeSymSubstituter(List(arg.symbol),List(selfsym)) + subs(rhs) } - if (attrError) annotationError - else AnnotationInfo(annType, constrArgs, nvPairs) } - // XXX what should the default case be doing here? - // see bug #1837 for code which induced a MatchError - case _ => annotationError + + def annInfo(t: Tree): AnnotationInfo = t match { + case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) => + AnnotationInfo(annType, args.map(AnnotationArgument(_)), List()) + + case Block(stats, expr) => + context.warning(t.pos, "Usage of named or default arguments transformed this annotation\n"+ + "constructor call into a block. The corresponding AnnotationInfo\n"+ + "will contain references to local values and default getters instead\n"+ + "of the actual argument trees") + annInfo(expr) + + case Apply(fun, args) => + context.warning(t.pos, "Implementation limitation: multiple argument lists on annotations are\n"+ + "currently not supported; ignoring arguments "+ args) + annInfo(fun) + + case _ => + error(t.pos, "unexpected tree after typing annotation: "+ typedAnn) + } + + if (annType.typeSymbol == DeprecatedAttr && + (argss.length == 0 || argss.head.length == 0)) + unit.deprecationWarning(ann.pos, + "the `deprecated' annotation now takes a (message: String) as parameter\n"+ + "indicating the reason for deprecation. That message is printed to the console and included in scaladoc.") + + if ((typedAnn.tpe == null) || typedAnn.tpe.isErroneous) annotationError + else annInfo(typedAnn) + } } } @@ -2461,19 +2556,19 @@ trait Typers { self: Analyzer => t match { case ExistentialType(tparams, _) => boundSyms ++= tparams - case AnnotatedType(annots, _, _) => - for (annot <- annots; arg <- annot.args; t <- arg.intTree) { - t match { - case Ident(_) => - // Check the symbol of an Ident, unless the - // Ident's type is already over an existential. - // (If the type is already over an existential, + case AnnotatedType(annots, _, _) => + for (annot <- annots; arg <- annot.args; t <- arg.intTree) { + t match { + case Ident(_) => + // Check the symbol of an Ident, unless the + // Ident's type is already over an existential. + // (If the type is already over an existential, // then remap the type, not the core symbol.) - if (!t.tpe.typeSymbol.hasFlag(EXISTENTIAL)) - addIfLocal(t.symbol, t.tpe) - case _ => () - } - } + if (!t.tpe.typeSymbol.hasFlag(EXISTENTIAL)) + addIfLocal(t.symbol, t.tpe) + case _ => () + } + } case _ => } addIfLocal(t.termSymbol, t) @@ -2482,7 +2577,7 @@ trait Typers { self: Analyzer => } object substLocals extends TypeMap { - override val dropNonConstraintAnnotations = true + override val dropNonConstraintAnnotations = true def apply(t: Type): Type = t match { case TypeRef(_, sym, args) if (sym.isLocal && args.length > 0) => @@ -2493,22 +2588,22 @@ trait Typers { self: Analyzer => case _ => mapOver(t) } - override def mapOver(arg: Tree, giveup: ()=>Nothing) = { - object substLocalTrees extends TypeMapTransformer { - override def transform(tr: Tree) = { + override def mapOver(arg: Tree, giveup: ()=>Nothing) = { + object substLocalTrees extends TypeMapTransformer { + override def transform(tr: Tree) = { localInstances.get(new SymInstance(tr.symbol, tr.tpe)) match { - case Some(local) => - Ident(local.existentialToString) - .setSymbol(tr.symbol).copyAttrs(tr).setType( - typeRef(NoPrefix, local, List())) + case Some(local) => + Ident(local.existentialToString) + .setSymbol(tr.symbol).copyAttrs(tr).setType( + typeRef(NoPrefix, local, List())) - case None => super.transform(tr) - } - } - } + case None => super.transform(tr) + } + } + } - substLocalTrees.transform(arg) - } + substLocalTrees.transform(arg) + } } val normalizedTpe = normalizeLocals(tree.tpe) @@ -2548,70 +2643,71 @@ trait Typers { self: Analyzer => case _ => NoType } - def typedAnnotated(annot: Annotation, arg1: Tree): Tree = { + def typedAnnotated(ann: Tree, arg1: Tree): Tree = { /** mode for typing the annotation itself */ val annotMode = mode & ~TYPEmode | EXPRmode if (arg1.isType) { - val selfsym = - if (!settings.selfInAnnots.value) - NoSymbol - else - arg1.tpe.selfsym match { - case NoSymbol => - /* Implementation limitation: Currently this - * can cause cyclical reference errors even - * when the self symbol is not referenced at all. - * Surely at least some of these cases can be - * fixed by proper use of LazyType's. Lex tinkered - * on this but did not succeed, so is leaving - * it alone for now. Example code with the problem: - * class peer extends Annotation - * class NPE[T <: NPE[T] @peer] - * - * (Note: -Yself-in-annots must be on to see the problem) - **/ - val sym = - newLocalDummy(context.owner, annot.pos) - .newValue(annot.pos, nme.self) - sym.setInfo(arg1.tpe.withoutAttributes) - sym - case sym => sym - } + // make sure the annotation is only typechecked once + if (ann.tpe == null) { + // an annotated type + val selfsym = + if (!settings.selfInAnnots.value) + NoSymbol + else + arg1.tpe.selfsym match { + case NoSymbol => + /* Implementation limitation: Currently this + * can cause cyclical reference errors even + * when the self symbol is not referenced at all. + * Surely at least some of these cases can be + * fixed by proper use of LazyType's. Lex tinkered + * on this but did not succeed, so is leaving + * it alone for now. Example code with the problem: + * class peer extends Annotation + * class NPE[T <: NPE[T] @peer] + * + * (Note: -Yself-in-annots must be on to see the problem) + **/ + val sym = + newLocalDummy(context.owner, ann.pos) + .newValue(ann.pos, nme.self) + sym.setInfo(arg1.tpe.withoutAnnotations) + sym + case sym => sym + } - // use the annotation context's owner as parent for symbols defined - // inside a type annotation - val ainfo = typedAnnotation(annot, context.owner, annotMode, selfsym) - val atype0 = arg1.tpe.withAttribute(ainfo) - val atype = - if ((selfsym != NoSymbol) && (ainfo.refsSymbol(selfsym))) - atype0.withSelfsym(selfsym) - else - atype0 // do not record selfsym if - // this annotation did not need it + val ainfo = typedAnnotation(ann, annotMode, selfsym) + val atype0 = arg1.tpe.withAnnotation(ainfo) + val atype = + if ((selfsym != NoSymbol) && (ainfo.refsSymbol(selfsym))) + atype0.withSelfsym(selfsym) + else + atype0 // do not record selfsym if + // this annotation did not need it - if (ainfo.isErroneous) - arg1 // simply drop erroneous annotations - else - TypeTree(atype) setOriginal tree + if (ainfo.isErroneous) + arg1 // simply drop erroneous annotations + else { + ann.tpe = atype + TypeTree(atype) setOriginal tree + } + } else { + // the annotation was typechecked before + TypeTree(ann.tpe) setOriginal tree + } } else { + // An annotated term, created with annotation ascription + // term : @annot() def annotTypeTree(ainfo: AnnotationInfo): Tree = - TypeTree(arg1.tpe.withAttribute(ainfo)) setOriginal tree + TypeTree(arg1.tpe.withAnnotation(ainfo)) setOriginal tree - val annotInfo = typedAnnotation(annot, context.owner, annotMode) - - arg1 match { - case _: DefTree => - if (!annotInfo.atp.isError) { - val attributed = - if (arg1.symbol.isModule) arg1.symbol.moduleClass else arg1.symbol - attributed.attributes = annotInfo :: attributed.attributes - } - arg1 - case _ => - val atpt = annotTypeTree(annotInfo) - Typed(arg1, atpt) setPos tree.pos setType atpt.tpe + if (ann.tpe == null) { + val annotInfo = typedAnnotation(ann, annotMode) + ann.tpe = arg1.tpe.withAnnotation(annotInfo) } + val atype = ann.tpe + Typed(arg1, TypeTree(atype) setOriginal tree) setPos tree.pos setType atype } } @@ -2957,9 +3053,9 @@ trait Typers { self: Analyzer => if (treeInfo.isVariableOrGetter(qual1)) { convertToAssignment(fun, qual1, name, args, ex) } else { - if ((qual1.symbol ne null) && qual1.symbol.isValue) - error(tree.pos, "reassignment to val") - else + if ((qual1.symbol ne null) && qual1.symbol.isValue) + error(tree.pos, "reassignment to val") + else reportTypeError(fun.pos, ex) setError(tree) } @@ -3382,14 +3478,8 @@ trait Typers { self: Analyzer => if ((comments ne null) && (defn.symbol ne null) && (defn.symbol ne NoSymbol)) comments(defn.symbol) = comment ret - case Annotation(constr, elements) => - val typedConstr = typed(constr, mode, WildcardType) - val typedElems = elements.map(typed(_, mode, WildcardType)) - (treeCopy.Annotation(tree, typedConstr, typedElems) - setType typedConstr.tpe) - - case Annotated(annot, arg) => - typedAnnotated(annot, typed(arg, mode, pt)) + case Annotated(constr, arg) => + typedAnnotated(constr, typed(arg, mode, pt)) case tree @ Block(_, _) => newTyper(context.makeNewScope(tree, context.owner)(BlockScopeKind(context.depth))) diff --git a/src/compiler/scala/tools/nsc/typechecker/Variances.scala b/src/compiler/scala/tools/nsc/typechecker/Variances.scala index 920b856094..22a90e7542 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Variances.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Variances.scala @@ -64,14 +64,14 @@ trait Variances { v } - /** Compute variance of type parameter `tparam' in all type annotations `attribs'. */ - def varianceInAttribs(attribs: List[AnnotationInfo])(tparam: Symbol): Int = { - (VARIANCES /: attribs) ((v, attrib) => v & varianceInAttrib(attrib)(tparam)) + /** Compute variance of type parameter `tparam' in all type annotations `annots'. */ + def varianceInAttribs(annots: List[AnnotationInfo])(tparam: Symbol): Int = { + (VARIANCES /: annots) ((v, annot) => v & varianceInAttrib(annot)(tparam)) } - /** Compute variance of type parameter `tparam' in type annotation `attrib'. */ - def varianceInAttrib(attrib: AnnotationInfo)(tparam: Symbol): Int = { - varianceInType(attrib.atp)(tparam) + /** Compute variance of type parameter `tparam' in type annotation `annot'. */ + def varianceInAttrib(annot: AnnotationInfo)(tparam: Symbol): Int = { + varianceInType(annot.atp)(tparam) } /** Compute variance of type parameter <code>tparam</code> in type <code>tp</code>. */ @@ -93,7 +93,7 @@ trait Variances { flip(varianceInSyms(tparams)(tparam)) & varianceInType(restpe)(tparam) case ExistentialType(tparams, restpe) => varianceInSyms(tparams)(tparam) & varianceInType(restpe)(tparam) - case AnnotatedType(attribs, tp, _) => - varianceInAttribs(attribs)(tparam) & varianceInType(tp)(tparam) + case AnnotatedType(annots, tp, _) => + varianceInAttribs(annots)(tparam) & varianceInType(tp)(tparam) } } diff --git a/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala b/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala index a25d73a08a..87c00e7b3d 100644 --- a/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala +++ b/src/compiler/scala/tools/nsc/util/FreshNameCreator.scala @@ -11,14 +11,14 @@ import scala.collection.mutable.HashMap trait FreshNameCreator { /** do not call before after type checking ends. - * Use <code>newName(Position, String)</code> instead. */ - @deprecated def newName(prefix: String): String + @deprecated("use newName(Position, String) instead") + def newName(prefix: String): String /** do not call before after type checking ends. - * Use newName(Position) instead. */ - @deprecated def newName(): String + @deprecated("use newName(Position) instead") + def newName(): String def newName(pos: util.Position, prefix: String): String def newName(pos: util.Position): String diff --git a/src/compiler/scala/tools/nsc/util/Set.scala b/src/compiler/scala/tools/nsc/util/Set.scala index 42c865e1b2..9ceb30d0ac 100644 --- a/src/compiler/scala/tools/nsc/util/Set.scala +++ b/src/compiler/scala/tools/nsc/util/Set.scala @@ -16,7 +16,7 @@ abstract class Set[T <: AnyRef] { def iterator: Iterator[T] - @deprecated def elements = iterator + @deprecated("use `iterator' instead") def elements = iterator def contains(x: T): Boolean = findEntry(x) ne null diff --git a/src/compiler/scala/tools/nsc/util/ShowPickled.scala b/src/compiler/scala/tools/nsc/util/ShowPickled.scala index 633fa5adf5..a98fee2848 100644 --- a/src/compiler/scala/tools/nsc/util/ShowPickled.scala +++ b/src/compiler/scala/tools/nsc/util/ShowPickled.scala @@ -52,7 +52,6 @@ object ShowPickled extends Names { case LITERALstring => "LITERALstring" case LITERALnull => "LITERALnull" case LITERALclass => "LITERALclass" - case ATTRIBUTE => "ATTRIBUTE" case CHILDREN => "CHILDREN" case PosTYPEsym => "PosTYPEsym" case PosALIASsym => "PosALIASsym" @@ -157,8 +156,6 @@ object ShowPickled extends Names { out.print(" <null>") case LITERALclass => printTypeRef() - case ATTRIBUTE => - printSymbolRef(); printTypeRef(); buf.until(end, printConstantRef) case CHILDREN => printSymbolRef(); buf.until(end, printSymbolRef) case _ => |