summaryrefslogtreecommitdiff
path: root/sources/scala/tools/nsc/typechecker/SyntheticMethods.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2005-09-20 17:45:45 +0000
committerMartin Odersky <odersky@gmail.com>2005-09-20 17:45:45 +0000
commit3761cb4b3a1c03f5daa2fac28d19f6f398072ffe (patch)
treeaf915e38284d71f68b9986f7050e0aa5555345f0 /sources/scala/tools/nsc/typechecker/SyntheticMethods.scala
parenta2231f55a00c96ecf670e0f02ed026c0ff956ecc (diff)
downloadscala-3761cb4b3a1c03f5daa2fac28d19f6f398072ffe.tar.gz
scala-3761cb4b3a1c03f5daa2fac28d19f6f398072ffe.tar.bz2
scala-3761cb4b3a1c03f5daa2fac28d19f6f398072ffe.zip
*** empty log message ***
Diffstat (limited to 'sources/scala/tools/nsc/typechecker/SyntheticMethods.scala')
-rwxr-xr-xsources/scala/tools/nsc/typechecker/SyntheticMethods.scala108
1 files changed, 108 insertions, 0 deletions
diff --git a/sources/scala/tools/nsc/typechecker/SyntheticMethods.scala b/sources/scala/tools/nsc/typechecker/SyntheticMethods.scala
new file mode 100755
index 0000000000..dafad66d54
--- /dev/null
+++ b/sources/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -0,0 +1,108 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author
+ */
+// $Id$
+package scala.tools.nsc.typechecker;
+
+import symtab.Flags._;
+import util.ListBuffer;
+
+abstract class SyntheticMethods: Analyzer {
+ import global._; // the global environment
+ import definitions._; // standard classes and methods
+ import typer.{typed}; // methods to type trees
+
+ def addSyntheticMethods(templ: Template, clazz: Symbol): Template = {
+
+ def hasImplementation(name: Name): boolean = {
+ val sym = clazz.info.nonPrivateMember(name);
+ sym.isTerm &&
+ (sym.owner == clazz ||
+ !(ObjectClass isSubClass sym.owner) && !(sym hasFlag DEFERRED));
+ }
+
+ def syntheticMethod(name: Name, flags: int, tpe: Type) = {
+ val method = clazz.newMethod(clazz.pos, name) setFlag (flags | OVERRIDE) setInfo tpe;
+ clazz.info.decls.enter(method);
+ method
+ }
+
+ def caseElementMethod: Tree = {
+ val method = syntheticMethod(
+ nme.caseElement, FINAL, MethodType(List(IntClass.tpe), AnyClass.tpe));
+ val caseFields = clazz.caseFieldAccessors map gen.mkRef;
+ typed(
+ DefDef(method, vparamss =>
+ if (caseFields.isEmpty) Literal(Constant(null))
+ else {
+ var i = caseFields.length;
+ var cases = List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(null))));
+ for (val field <- caseFields.reverse) {
+ i = i - 1; cases = CaseDef(Literal(Constant(i)), EmptyTree, field) :: cases
+ }
+ Match(Ident(vparamss.head.head), cases)
+ }))
+ }
+
+ def caseArityMethod: Tree = {
+ val method = syntheticMethod(nme.caseArity, FINAL, PolyType(List(), IntClass.tpe));
+ typed(DefDef(method, vparamss => Literal(Constant(clazz.caseFieldAccessors.length))))
+ }
+
+ def caseNameMethod: Tree = {
+ val method = syntheticMethod(nme.caseName, FINAL, PolyType(List(), StringClass.tpe));
+ typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode))))
+ }
+
+ def moduleToStringMethod: Tree = {
+ val method = syntheticMethod(nme.toString_, FINAL, MethodType(List(), StringClass.tpe));
+ typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode))))
+ }
+
+ def tagMethod: Tree = {
+ val method = syntheticMethod(nme.tag, FINAL, MethodType(List(), IntClass.tpe));
+ typed(DefDef(method, vparamss => Literal(Constant(clazz.tag))))
+ }
+
+ def forwardingMethod(name: Name): Tree = {
+ val target = getMember(ScalaRunTimeModule, "_" + name);
+ val method = syntheticMethod(
+ name, 0, MethodType(target.tpe.paramTypes.tail, target.tpe.resultType));
+ typed(DefDef(method, vparamss =>
+ Apply(gen.mkRef(target), This(clazz) :: (vparamss.head map Ident))));
+ }
+
+ def readResolveMethod: Tree = {
+ // !!! the synthetic method "readResolve" should be private,
+ // but then it is renamed !!!
+ val method = syntheticMethod(nme.readResolve, PROTECTED, MethodType(List(), ObjectClass.tpe));
+ typed(DefDef(method, vparamss => gen.mkRef(clazz.sourceModule)))
+ }
+
+ val ts = new ListBuffer[Tree];
+ if (clazz hasFlag CASE) {
+ if (!hasImplementation(nme.tag)) ts += tagMethod;
+ if (clazz.isModuleClass) {
+ if (!hasImplementation(nme.toString_)) ts += moduleToStringMethod;
+ if (clazz.isSubClass(SerializableClass)) {
+ // 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)
+ if (!hasImplementation(nme.readResolve)) ts += readResolveMethod;
+ }
+ } else {
+ if (!hasImplementation(nme.caseElement)) ts += caseElementMethod;
+ if (!hasImplementation(nme.caseArity)) ts += caseArityMethod;
+ if (!hasImplementation(nme.caseName)) ts += caseNameMethod;
+ if (!hasImplementation(nme.equals_)) ts += forwardingMethod(nme.equals_);
+ if (!hasImplementation(nme.hashCode_)) ts += forwardingMethod(nme.hashCode_);
+ if (!hasImplementation(nme.toString_)) ts += forwardingMethod(nme.toString_);
+ }
+ }
+ val synthetics = ts.toList;
+ copy.Template(
+ templ, templ.parents, if (synthetics.isEmpty) templ.body else templ.body ::: synthetics)
+ }
+}