summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreePrinters.scala18
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala19
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala19
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala33
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala28
7 files changed, 95 insertions, 28 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
index f428e13411..da734729b3 100644
--- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
@@ -100,9 +100,21 @@ abstract class TreePrinters {
}
def printAttributes(attrs: List[AttrInfo]): unit = {
- def attrToString(attr: AttrInfo): String = attr match {
- case Pair(tp, List()) => tp.toString()
- case Pair(tp, args) => tp.toString()+args.mkString("(", ",", ")")
+ def attrToString(attr: AttrInfo): String = {
+ val str = new StringBuffer()
+ attr match {
+ case Triple(tp, args, nvPairs) =>
+ str.append(tp.toString());
+ if (!args.isEmpty)
+ str.append(args.mkString("(", ",", ")"))
+ if (!nvPairs.isEmpty)
+ for (val Pair(Pair(sym, value), index) <- nvPairs.zipWithIndex) {
+ if (index > 0)
+ str.append(", ")
+ str.append(sym.name).append(" = ").append(value)
+ }
+ str.toString
+ }
}
if (!attrs.isEmpty) print(attrs.map(attrToString).mkString("[", ",", "]"))
}
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index c475ece753..35396d22f4 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -307,7 +307,11 @@ trait Trees requires Global {
case class Import(expr: Tree, selectors: List[Pair[Name, Name]])
extends SymTree;
- /** Attribuetd definition */
+ /** Attribute application (constructor arguments + name-value pairs) */
+ case class Attribute(constr: Tree, elements: List[Tree])
+ extends TermTree;
+
+ /** Attributed definition */
case class Attributed(attribute: Tree, definition: Tree)
extends Tree {
override def symbol: Symbol = definition.symbol;
@@ -553,6 +557,7 @@ trait Trees requires Global {
case AliasTypeDef(mods, name, tparams, rhs) => (eliminated by erasure)
case LabelDef(name, params, rhs) =>
case Import(expr, selectors) => (eliminated by typecheck)
+ case Attribute(constr, elements) => (eliminated by typecheck)
case Attributed(attribute, definition) => (eliminated by typecheck)
case DocDef(comment, definition) => (eliminated by typecheck)
case Template(parents, body) =>
@@ -596,6 +601,7 @@ trait Trees requires Global {
def AliasTypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[AbsTypeDef], rhs: Tree): AliasTypeDef;
def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree): LabelDef;
def Import(tree: Tree, expr: Tree, selectors: List[Pair[Name, Name]]): Import;
+ def Attribute(tree: Tree, constr: Tree, elements: List[Tree]): Attribute;
def Attributed(tree: Tree, attribute: Tree, definition: Tree): Attributed;
def DocDef(tree: Tree, comment: String, definition: Tree): DocDef;
def Template(tree: Tree, parents: List[Tree], body: List[Tree]): Template;
@@ -648,6 +654,8 @@ trait Trees requires Global {
new LabelDef(name, params, rhs).copyAttrs(tree);
def Import(tree: Tree, expr: Tree, selectors: List[Pair[Name, Name]]) =
new Import(expr, selectors).copyAttrs(tree);
+ def Attribute(tree: Tree, constr: Tree, elements: List[Tree]) =
+ new Attribute(constr, elements);
def Attributed(tree: Tree, attribute: Tree, definition: Tree) =
new Attributed(attribute, definition).copyAttrs(tree);
def DocDef(tree: Tree, comment: String, definition: Tree) =
@@ -759,6 +767,11 @@ trait Trees requires Global {
if ((expr0 == expr) && (selectors0 == selectors)) => t
case _ => copy.Import(tree, expr, selectors)
}
+ def Attribute(tree: Tree, constr: Tree, elements: List[Tree]) = tree match {
+ case t @ Attribute(constr0, elements0)
+ if ((constr0 == constr) && (elements0 == elements)) => t
+ case _ => copy.Attribute(tree, constr, elements)
+ }
def Attributed(tree: Tree, attribute: Tree, definition: Tree) = tree match {
case t @ Attributed(attribute0, definition0)
if ((attribute0 == attribute) && (definition0 == definition)) => t
@@ -954,6 +967,8 @@ trait Trees requires Global {
copy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LamdaLifter.proxy'
case Import(expr, selectors) =>
copy.Import(tree, transform(expr), selectors)
+ case Attribute(constr, elements) =>
+ copy.Attribute(tree, transform(constr), transformTrees(elements))
case Attributed(attribute, definition) =>
copy.Attributed(tree, transform(attribute), transform(definition))
case DocDef(comment, definition) =>
@@ -1084,6 +1099,8 @@ trait Trees requires Global {
traverseTrees(params); traverse(rhs)
case Import(expr, selectors) =>
traverse(expr)
+ case Attribute(constr, elements) =>
+ traverse(constr); traverseTrees(elements);
case Attributed(attribute, definition) =>
traverse(attribute); traverse(definition)
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 979f273529..c0eb751e06 100644
--- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -1791,12 +1791,29 @@ trait Parsers requires SyntaxAnalyzer {
/** Attribute ::= StableId [TypeArgs] [`(' [Exprs] `)']
*/
def attribute(): Tree = {
+ def nameValuePair(): Tree = {
+ var pos = in.currentPos;
+ val aname = atPos(pos) { Ident(ident()) }
+ accept(EQUALS);
+ atPos(pos) { Assign(aname, prefixExpr()) }
+ }
val pos = in.currentPos;
var t: Tree = convertToTypeId(stableId());
if (in.token == LBRACKET)
t = atPos(in.currentPos)(AppliedTypeTree(t, typeArgs()));
val args = if (in.token == LPAREN) argumentExprs() else List();
- atPos(pos) { New(t, List(args)) }
+ 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 = atPos(pos) { New(t, List(args)) }
+ atPos(pos) { Attribute(constr, nameValuePairs) }
}
def mixinAttribute(attrs: List[Tree]) = {
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 6a6239e3ea..69a008679d 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -125,13 +125,13 @@ abstract class GenJVM extends SubComponent {
parents = definitions.ObjectClass.tpe :: parents;
c.symbol.attributes foreach { a => a match {
- case Pair(SerializableAttr, _) if (!forCLDC) =>
+ case Triple(SerializableAttr, _, _) if (!forCLDC) =>
parents = parents ::: List(definitions.SerializableClass.tpe);
- case Pair(CloneableAttr, _) if (!forCLDC) =>
+ case Triple(CloneableAttr, _, _) if (!forCLDC) =>
parents = parents ::: List(CloneableClass.tpe);
- case Pair(SerialVersionUID, value :: _) if (!forCLDC) =>
+ case Triple(SerialVersionUID, value :: _, _) if (!forCLDC) =>
serialVUID = Some(value.longValue);
- case Pair(RemoteAttr, _) if (!forCLDC) =>
+ case Triple(RemoteAttr, _, _) if (!forCLDC) =>
parents = parents ::: List(RemoteInterface.tpe);
remoteClass = true;
case _ => ();
@@ -178,7 +178,7 @@ abstract class GenJVM extends SubComponent {
def addExceptionsAttribute(jm: JMethod, throws: List[AttrInfo]): Unit = {
if (throws.forall(a => a match {
- case Pair(ThrowsAttr, _) => false
+ case Triple(ThrowsAttr, _, _) => false
case _ => true
})) return;
@@ -189,7 +189,7 @@ abstract class GenJVM extends SubComponent {
// put some radom value; the actual number is determined at the end
buf.putShort(0xbaba.toShort)
- for (val Pair(ThrowsAttr, List(exc)) <- throws) {
+ for (val Triple(ThrowsAttr, List(exc), _) <- throws) {
buf.putShort(cpool.addClass(exc.typeValue.toString()).shortValue)
nattr = nattr + 1;
}
@@ -215,13 +215,12 @@ abstract class GenJVM extends SubComponent {
// put some radom value; the actual number is determined at the end
buf.putShort(0xbaba.toShort)
- for (val Pair(typ, consts) <- attributes; typ.symbol.hasFlag(Flags.JAVA)) {
+ for (val Triple(typ, consts, nvPairs) <- attributes; typ.symbol.hasFlag(Flags.JAVA)) {
nattr = nattr + 1;
val jtype = javaType(typ);
buf.putShort(cpool.addUtf8(jtype.getSignature()).toShort);
- assert(consts.length == 1, consts.toString())
- buf.putShort(1.toShort); // for now only 1 constructor parameter
- buf.putShort(cpool.addUtf8("value").toShort);
+ assert(consts.length <= 1, consts.toString())
+ buf.putShort((consts.length + nvPairs.length).toShort);
def emitElement(const: Constant): Unit = const.tag match {
case BooleanTag =>
buf.put('Z'.toByte)
@@ -264,9 +263,13 @@ abstract class GenJVM extends SubComponent {
for (val elem <- arr) emitElement(elem)
//case NullTag => AllRefClass.tpe
}
-
- for (val const <- consts) {
- emitElement(const)
+ if (!consts.isEmpty) {
+ buf.putShort(cpool.addUtf8("value").toShort);
+ emitElement(consts.head);
+ }
+ for (val Pair(symbol, value) <- nvPairs) {
+ buf.putShort(cpool.addUtf8(symbol.name.toString()).toShort)
+ emitElement(value)
}
}
if (nattr > 0) {
@@ -298,8 +301,8 @@ abstract class GenJVM extends SubComponent {
var attributes = 0;
f.symbol.attributes foreach { a => a match {
- case Pair(TransientAtt, _) => attributes = attributes | JAccessFlags.ACC_TRANSIENT;
- case Pair(VolatileAttr, _) => attributes = attributes | JAccessFlags.ACC_VOLATILE;
+ case Triple(TransientAtt, _, _) => attributes = attributes | JAccessFlags.ACC_TRANSIENT;
+ case Triple(VolatileAttr, _, _) => attributes = attributes | JAccessFlags.ACC_VOLATILE;
case _ => ();
}}
val jfield =
diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
index 65606e591d..816df859ba 100644
--- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala
@@ -20,7 +20,7 @@ trait Symbols requires SymbolTable {
var typeSymbolCount = 0
var classSymbolCount = 0
- type AttrInfo = Pair[Type, List[Constant]]
+ type AttrInfo = Triple[Type, List[Constant], List[Pair[Symbol,Constant]]]
val emptySymbolArray = new Array[Symbol](0)
@@ -133,7 +133,7 @@ trait Symbols requires SymbolTable {
final def newAnonymousFunctionClass(pos: int) = {
val anonfun = newClass(pos, nme.ANON_FUN_NAME.toTypeName)
anonfun.attributes =
- Pair(definitions.SerializableAttr.tpe, List()) :: anonfun.attributes
+ Triple(definitions.SerializableAttr.tpe, List(), List()) :: anonfun.attributes
anonfun
}
final def newRefinementClass(pos: int) =
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index a5c6abb92a..6dfda34435 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -168,7 +168,7 @@ trait SyntheticMethods requires Analyzer {
if (clazz hasFlag CASE) {
// case classes are implicitly declared serializable
- clazz.attributes = Pair(SerializableAttr.tpe, List()) :: clazz.attributes;
+ clazz.attributes = Triple(SerializableAttr.tpe, List(), List()) :: clazz.attributes;
for (val stat <- templ.body) {
if (stat.isDef && stat.symbol.isMethod && stat.symbol.hasFlag(CASEACCESSOR) &&
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 33599ef7ab..6effca1c70 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1350,17 +1350,35 @@ trait Typers requires Analyzer {
}
typer1.typedLabelDef(ldef)
- case Attributed(attr, defn) =>
- val attr1 = typed(attr, mode | CONSTmode, AttributeClass.tpe)
- val attrInfo = attr1 match {
+ case Attributed(Attribute(constr, elements), defn) =>
+ val constr1 = typed(constr, mode | CONSTmode, AttributeClass.tpe)
+ val attrInfo = constr1 match {
case Apply(Select(New(tpt), nme.CONSTRUCTOR), args) =>
- Pair(tpt.tpe, args map {
+ val constrArgs = args map {
case Literal(value) =>
value
case arg =>
error(arg.pos, "attribute argument needs to be a constant; found: "+arg)
null
- })
+ }
+ val nvPairs = elements map {
+ case Assign(Ident(name), rhs) => {
+ val sym = tpt.tpe.decls.lookupEntry(name).sym;
+ if (sym == NoSymbol) {
+ null
+ } else {
+ val rhs1 = typed(rhs, mode | CONSTmode, sym.tpe.resultType)
+ val value = rhs1 match {
+ case Literal(v) => v
+ case arg =>
+ error(arg.pos, "attribute argument needs to be a constant; found: "+arg)
+ null
+ }
+ Pair(sym, value)
+ }
+ }
+ }
+ Triple(tpt.tpe, constrArgs, nvPairs)
}
if (attrInfo != null) {
val attributed =