From 08d6815870d309e1ce924a99f17f50c6e46f89cd Mon Sep 17 00:00:00 2001 From: mihaylov Date: Sun, 29 May 2005 23:06:35 +0000 Subject: Initial support for attributes - only works for... Initial support for attributes - only works for the scala.serializable attribute --- config/list/scalac.lst | 1 + .../scala/tools/scalac/typechecker/Analyzer.scala | 17 ++++------ .../scala/tools/scalac/typechecker/RefCheck.scala | 18 ++++++---- sources/scalac/Global.java | 28 +++++++++++++++- sources/scalac/atree/AConstant.java | 2 ++ sources/scalac/backend/jvm/GenJVM.java | 9 ++++- sources/scalac/symtab/AttributeInfo.java | 39 ++++++++++++++++++++++ sources/scalac/symtab/Definitions.java | 16 ++++++--- sources/scalac/transformer/AddInterfacesPhase.java | 6 ++++ 9 files changed, 113 insertions(+), 23 deletions(-) create mode 100644 sources/scalac/symtab/AttributeInfo.java diff --git a/config/list/scalac.lst b/config/list/scalac.lst index b0f49ed7c2..747c1c2937 100644 --- a/config/list/scalac.lst +++ b/config/list/scalac.lst @@ -78,6 +78,7 @@ ../../../scalac/symtab/classfile/Pickle.java ../../../scalac/symtab/classfile/UnPickle.java +../../../scalac/symtab/AttributeInfo.java ../../../scalac/symtab/ClosureHistory.java ../../../scalac/symtab/Definitions.java ../../../scalac/symtab/EntryTags.java diff --git a/sources/scala/tools/scalac/typechecker/Analyzer.scala b/sources/scala/tools/scalac/typechecker/Analyzer.scala index facaafc7ee..9abd60ef20 100644 --- a/sources/scala/tools/scalac/typechecker/Analyzer.scala +++ b/sources/scala/tools/scalac/typechecker/Analyzer.scala @@ -56,8 +56,6 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( var unit: CompilationUnit = _; - type AttrInfo = Pair/**/ ; - def enterUnit(unit: CompilationUnit): unit = enter( new Context( @@ -2163,15 +2161,15 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( case Tree.Attributed(attr, definition) => - def attrInfo(attr: Tree): AttrInfo = attr match { + def attrInfo(attr: Tree): Tuple2[Symbol, Array[AConstant]] = attr match { case Tree.Ident(_) | Tree.Select(_, _) => - new Pair(attr.symbol(), new Array[AConstant](0)) + Tuple2(attr.symbol(), AConstant.EMPTY_ARRAY) case Tree.Apply(fn, args) => - new Pair(attrInfo(fn).fst, attrArgInfos(args)) + Tuple2(attrInfo(fn)._1, attrArgInfos(args)) case _ => unit.error(attr.pos, "malformed attribute"); - new Pair(Symbol.NONE.newErrorClass(errorName(attr).toTypeName()), - new Array[AConstant](0)) + Tuple2(Symbol.NONE.newErrorClass(errorName(attr).toTypeName()), + AConstant.EMPTY_ARRAY) } def attrArgInfos(args: Array[Tree]): Array[AConstant] = { @@ -2190,9 +2188,8 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( val attr1 = transform(attr, CONSTRmode, definitions.ATTRIBUTE_TYPE()); val res = transform(definition); val defsym = res.symbol(); - var attrs = global.mapSymbolAttr.get(defsym).asInstanceOf[List[AttrInfo]]; - if (attrs == null) attrs = List(); - global.mapSymbolAttr.put(defsym, attrInfo(attr1) :: attrs); + val attrpair = attrInfo(attr1); + global.addAttribute(defsym, attrpair._1, attrpair._2); res case Tree.DocDef(comment, definition) => diff --git a/sources/scala/tools/scalac/typechecker/RefCheck.scala b/sources/scala/tools/scalac/typechecker/RefCheck.scala index 42e208fe8e..8bee62c5ed 100755 --- a/sources/scala/tools/scalac/typechecker/RefCheck.scala +++ b/sources/scala/tools/scalac/typechecker/RefCheck.scala @@ -877,6 +877,7 @@ class RefCheck(globl: scalac.Global) extends Transformer(globl) { private def addSyntheticMethods(templ: Template, clazz: ClassSymbol): Template = { val ts = new TreeList(); if (clazz.isCaseClass()) { + global.addAttribute(clazz, defs.SCALA_SERIALIZABLE_CONSTR); if (!hasImplementation(clazz, Names.toString)) { ts.append(toStringMethod(clazz)); } @@ -900,12 +901,17 @@ class RefCheck(globl: scalac.Global) extends Transformer(globl) { if (global.target != Global.TARGET_MSIL) ts.append(getTypeMethod(clazz)); } - if (clazz.isModuleClass() && clazz.isSubClass(defs.SERIALIZABLE_CLASS)) { - // If you serialize a singleton and then deserialize it twice, - // you will have two instances of your singleton, unless you implement - // the readResolve() method (see http://www.javaworld.com/javaworld/ - // jw-04-2003/jw-0425-designpatterns_p.html) - ts.append(readResolveMethod(clazz)); + if (clazz.isModuleClass()) { + val attrs = global.getAttributes(clazz); + val serializable = attrs != null && + attrs.getAttrArguments(defs.SCALA_SERIALIZABLE_CONSTR) != null; + if (serializable) { + // If you serialize a singleton and then deserialize it twice, + // you will have two instances of your singleton, unless you implement + // the readResolve() method (see http://www.javaworld.com/javaworld/ + // jw-04-2003/jw-0425-designpatterns_p.html) + ts.append(readResolveMethod(clazz)); + } } copy.Template( templ, templ.parents, diff --git a/sources/scalac/Global.java b/sources/scalac/Global.java index 6c2b9ac200..6f6bb899a3 100644 --- a/sources/scalac/Global.java +++ b/sources/scalac/Global.java @@ -35,6 +35,7 @@ import scala.tools.util.ReporterTimer; import scalac.ast.*; import scalac.ast.parser.*; import scalac.ast.printer.TreePrinter; +import scalac.atree.AConstant; import scalac.atree.ATreePrinter; import scalac.backend.Primitives; // !!! <<< Interpreter stuff @@ -121,7 +122,7 @@ public abstract class Global { /** attributes of symbols */ - public final Map/*>*/ mapSymbolAttr = new HashMap(); + protected final Map/**/ mapSymbolAttr = new HashMap(); /** views associated with (upper-bounded) type parameters */ @@ -416,6 +417,31 @@ public abstract class Global { } } + public void addAttribute(Symbol sym, Symbol aSym, AConstant[] params) { + AttributeInfo attr = getAttributes(sym); + attr = new AttributeInfo(aSym, params, attr); + //mapSymbolAttr.put(sym, attr); + setAttribute(sym, attr); + } + + public void addAttribute(Symbol sym, Symbol aSym) { + addAttribute(sym, aSym, AConstant.EMPTY_ARRAY); + } + + public void setAttribute(Symbol sym, AttributeInfo attr) { + mapSymbolAttr.put(sym, attr); + if (sym.isModule() && !sym.isModuleClass()) + mapSymbolAttr.put(sym.moduleClass(), attr); + } + + public AttributeInfo getAttributes(Symbol sym) { + return (AttributeInfo)mapSymbolAttr.get(sym); + } + + public AttributeInfo removeAttributes(Symbol sym) { + return (AttributeInfo)mapSymbolAttr.remove(sym); + } + public abstract void dump(CompilationUnit[] units); void print(CompilationUnit[] units) { diff --git a/sources/scalac/atree/AConstant.java b/sources/scalac/atree/AConstant.java index 2dcc80bbaf..12c58d5889 100644 --- a/sources/scalac/atree/AConstant.java +++ b/sources/scalac/atree/AConstant.java @@ -14,6 +14,8 @@ import scalac.symtab.Symbol; /** This class represents a constant. */ public class AConstant { + public static final AConstant[] EMPTY_ARRAY = new AConstant[0]; + //######################################################################## // Public Cases diff --git a/sources/scalac/backend/jvm/GenJVM.java b/sources/scalac/backend/jvm/GenJVM.java index 5095a3b024..5753ca9c4d 100644 --- a/sources/scalac/backend/jvm/GenJVM.java +++ b/sources/scalac/backend/jvm/GenJVM.java @@ -1624,6 +1624,10 @@ public class GenJVM { protected Context enterClass(Context ctx, Symbol cSym) { String javaName = javaName(cSym); + AttributeInfo attrs = global.getAttributes(cSym); + boolean serializable = attrs != null + && attrs.getAttrArguments(defs.SCALA_SERIALIZABLE_CONSTR) != null; + scalac.symtab.Type[] baseTps = cSym.info().parents(); assert baseTps.length > 0 : Debug.show(cSym); @@ -1636,12 +1640,15 @@ public class GenJVM { offset = 1; superClassName = javaName(baseTps[0].symbol()); } - String[] interfaceNames = new String[baseTps.length - offset]; + String[] interfaceNames = new String[baseTps.length - offset + + (serializable ? 1 : 0)]; for (int i = offset; i < baseTps.length; ++i) { Symbol baseSym = baseTps[i].symbol(); assert baseSym.isInterface() : cSym + " implements " + baseSym; interfaceNames[i - offset] = javaName(baseSym); } + if (serializable) + interfaceNames[interfaceNames.length - 1] = "java.io.Serializable"; JClass cls = fjbgContext.JClass(javaModifiers(cSym) & ~JAccessFlags.ACC_STATIC diff --git a/sources/scalac/symtab/AttributeInfo.java b/sources/scalac/symtab/AttributeInfo.java new file mode 100644 index 0000000000..8269cc74a6 --- /dev/null +++ b/sources/scalac/symtab/AttributeInfo.java @@ -0,0 +1,39 @@ +package scalac.symtab; + +import scalac.atree.AConstant; +import scalac.util.Debug; + +public class AttributeInfo { + + public final Symbol constr; + public final AConstant[] args; + public final AttributeInfo next; + + public AttributeInfo(Symbol constr, AConstant[] args, AttributeInfo next) { + this.constr = constr; + this.args = args; + this.next = next; + assert constr.isConstructor() : Debug.show(constr); + } + + public AConstant[] getAttrArguments(Symbol sym) { + for (AttributeInfo attr = this; attr != null; attr = attr.next) + if (attr.constr == sym) + return attr.args; + return null; + } + + public String toString() { + StringBuffer str = new StringBuffer(); + for (AttributeInfo attr = this; attr != null; attr = attr.next) { + str.append('['); str.append(Debug.show(attr.constr.constructorClass())); + str.append('('); + for (int i = 0; i < attr.args.length; i++) { + if (i > 0) str.append(", "); + str.append(attr.args[i]); + } + str.append(")]\n"); + } + return str.toString(); + } +} diff --git a/sources/scalac/symtab/Definitions.java b/sources/scalac/symtab/Definitions.java index 11b49d1f57..a80ceeff52 100644 --- a/sources/scalac/symtab/Definitions.java +++ b/sources/scalac/symtab/Definitions.java @@ -77,10 +77,6 @@ public class Definitions { public final Symbol THROWABLE_CLASS; public final Type THROWABLE_TYPE() {return THROWABLE_CLASS.staticType();} - /** The java.io.Serializable class */ - public final Symbol SERIALIZABLE_CLASS; - public final Type SERIALIZABLE_TYPE() {return SERIALIZABLE_CLASS.staticType();} - //######################################################################## // Public Fields & Methods - Scala value classes @@ -253,6 +249,12 @@ public class Definitions { /** The scala.MatchError module */ public final Symbol MATCHERROR; + //######################################################################## + // attributes + + public final Symbol SCALA_SERIALIZABLE_CONSTR; + public final Symbol SCALA_SERIAL_VERSION_UID_CONSTR; + //######################################################################## // Public Fields & Methods - Scala primitive types @@ -789,7 +791,6 @@ public class Definitions { STRING_CLASS = getClass(forMSIL ? "System.String" : "java.lang.String"); THROWABLE_CLASS = getClass(forMSIL ? "System.Exception" : "java.lang.Throwable"); - SERIALIZABLE_CLASS = getClass("java.io.Serializable"); // the scala value classes UNIT_CLASS = getClass("scala.Unit"); @@ -833,6 +834,11 @@ public class Definitions { CONSOLE = getModule("scala.Console"); MATCHERROR = getModule("scala.MatchError"); + SCALA_SERIALIZABLE_CONSTR = getClass("scala.serializable") + .primaryConstructor(); + SCALA_SERIAL_VERSION_UID_CONSTR = getClass("scala.SerialVersionUID") + .primaryConstructor(); + // initialize generated classes and aliases initClass(ANY_CLASS, Type.EMPTY_ARRAY); initAlias(ANYREF_CLASS, OBJECT_TYPE()); diff --git a/sources/scalac/transformer/AddInterfacesPhase.java b/sources/scalac/transformer/AddInterfacesPhase.java index aa2eb23ebb..60c8ef441d 100644 --- a/sources/scalac/transformer/AddInterfacesPhase.java +++ b/sources/scalac/transformer/AddInterfacesPhase.java @@ -256,6 +256,12 @@ public class AddInterfacesPhase extends Phase { classSym)); ifaceToClass.put(ifaceSym, classSym); classToIFace.put(classSym, ifaceSym); + + // move attributes to the implementing class + AttributeInfo attr = global.removeAttributes(ifaceSym); + if (attr != null) { + global.setAttribute(classSym, attr); + } } return classSym; } -- cgit v1.2.3