summaryrefslogtreecommitdiff
path: root/sources/scala/tools/nsc/transform/ExplicitOuter.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2005-08-03 22:18:10 +0000
committerMartin Odersky <odersky@gmail.com>2005-08-03 22:18:10 +0000
commit2a5f62338c30ba6d06aa10c8fb809ce92462f96c (patch)
tree052924741ede17387be41de5e9ff0d13d0d59fd4 /sources/scala/tools/nsc/transform/ExplicitOuter.scala
parente12958a079cbffcfdb8142ab668581664f671334 (diff)
downloadscala-2a5f62338c30ba6d06aa10c8fb809ce92462f96c.tar.gz
scala-2a5f62338c30ba6d06aa10c8fb809ce92462f96c.tar.bz2
scala-2a5f62338c30ba6d06aa10c8fb809ce92462f96c.zip
*** empty log message ***
Diffstat (limited to 'sources/scala/tools/nsc/transform/ExplicitOuter.scala')
-rwxr-xr-xsources/scala/tools/nsc/transform/ExplicitOuter.scala366
1 files changed, 366 insertions, 0 deletions
diff --git a/sources/scala/tools/nsc/transform/ExplicitOuter.scala b/sources/scala/tools/nsc/transform/ExplicitOuter.scala
new file mode 100755
index 0000000000..f1ac3392e8
--- /dev/null
+++ b/sources/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -0,0 +1,366 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author
+ */
+// $Id$
+package scala.tools.nsc.transform;
+
+import symtab._;
+import Flags._;
+import util.ListBuffer;
+import collection.mutable.HashMap;
+
+abstract class ExplicitOuter extends InfoTransform {
+ import global._;
+ import definitions._;
+ import posAssigner.atPos;
+
+ override def phaseNewFlags: long = notPRIVATE | notPROTECTED;
+
+ /** the following two members override abstract members in Transform */
+ val phaseName: String = "explicitouter";
+
+ final val needSuperAccessors = false;
+
+ protected def newTransformer(unit: CompilationUnit): Transformer =
+ new ExplicitOuterTransformer(unit);
+
+ /** The type transformation method:
+ * 1. Add an outer paramter to the formal parameters of a constructor or mixin constructor
+ * in a non-static class;
+ * 2. Add a mixin constructor $init$ to all traits except interfaces
+ * Leave all other types unchanged.
+ */
+ override def transformInfo(sym: Symbol, tp: Type): Type = tp match {
+ case MethodType(formals, restpe) =>
+ if ((sym.isConstructor || sym.isMixinConstructor) && !sym.owner.isStatic)
+ MethodType(formals ::: List(sym.owner.owner.enclClass.thisType), restpe)
+ else tp;
+ case ClassInfoType(parents, decls, clazz) =>
+ var decls1 = decls;
+ if (!(clazz hasFlag INTERFACE)) {
+ if (!clazz.isStatic) {
+ decls1 = new Scope(decls1.toList);
+ val outerType = clazz.owner.enclClass.thisType;
+ decls1 enter (clazz.newValue(clazz.pos, nme.LOCAL_NAME(nme.OUTER))
+ setFlag (LOCAL | PRIVATE | PARAMACCESSOR)
+ setInfo outerType);
+ decls1 enter (clazz.newMethod(clazz.pos, nme.OUTER)
+ setFlag (PRIVATE | PARAMACCESSOR | ACCESSOR | STABLE | FINAL)
+ setInfo MethodType(List(), outerType));
+ }
+ if (clazz.isTrait) {
+ decls1 = new Scope(decls1.toList);
+ decls1 enter makeMixinConstructor(clazz);
+ }
+ }
+ if (decls1 eq decls) tp else ClassInfoType(parents, decls1, clazz)
+ case PolyType(tparams, restp) =>
+ val restp1 = transformInfo(sym, restp);
+ if (restp eq restp1) tp else PolyType(tparams, restp1)
+ case _ =>
+ tp
+ }
+
+ private def makeMixinConstructor(clazz: Symbol): Symbol =
+ clazz.newMethod(clazz.pos, nme.MIXIN_CONSTRUCTOR) setInfo MethodType(List(), UnitClass.tpe);
+
+ class ExplicitOuterTransformer(unit: CompilationUnit) extends Transformer {
+
+ /** A map that takes triples consisting of
+ * - the class symbol that contains the accessor
+ * - the symbol accessed by the accessor
+ * - the mixin qualifier of the symbol
+ * to super accessor symbols.
+ * //todo: not clear whether we need to this for all super calls symbols, or just
+ * protected ones (or all calls to protected from inner classes)?
+ */
+ private val superAccessors = new HashMap[Triple[Symbol, Symbol, Name], Symbol];
+
+ /** Generate a superclass accessor symbol and enter in `superAccessors' unless one
+ * exists already.
+ */
+ def superAccessor(clazz: Symbol, accessed: Symbol, mix: Name): Symbol =
+ superAccessors.get(Triple(clazz, accessed, mix)) match {
+ case Some(accessor) =>
+ accessor
+ case None =>
+ val accessor = makeSuperAccessor(clazz, accessed, mix);
+ superAccessors(Triple(clazz, accessed, mix)) = accessor;
+ accessor
+ }
+
+ /** Generate a superclass acessor symbol named `NAME$super$MIX' in class `class'
+ * where NAME is the name of the accessed symbol `accessed'
+ * and MIX is the mixin qualifier of the super call `mix'.
+ * The method is initially `private'; will be widened later
+ */
+ def makeSuperAccessor(clazz: Symbol, accessed: Symbol, mix: Name): Symbol = {
+ assert(accessed.isMethod);
+ val accessorName = newTermName(
+ accessed.name.toString() + "$super" +
+ (if (mix == nme.EMPTY.toTypeName) "" else "$" + mix));
+ val accessor = clazz.newMethod(clazz.pos, accessorName)
+ setFlag PRIVATE
+ setInfo clazz.tpe.memberType(accessed);
+ clazz.info.decls enter accessor;
+ accessor
+ }
+
+ /** The path
+ * `from'.this.$outer ... .$outer
+ * which is equivalent to an outer self reference `to'.this from within class `from'
+ */
+ def outerPath(base: Tree, to: Symbol): Tree =
+ if (base.tpe.symbol == to) base else outerPath(outerSelect(base), to);
+
+ /** Select and apply outer accessor from `base'
+ */
+ def outerSelect(base: Tree): Tree = {
+ assert(base.tpe != null, base);
+ assert(base.tpe.symbol != null, base);
+ val clazz = base.tpe.symbol.owner.enclClass;
+ Apply(
+ Select(base, base.tpe.member(nme.OUTER)) setType MethodType(List(), clazz.thisType),
+ List()) setType clazz.thisType;
+ }
+
+ /** The first step performs the following transformations:
+ * 1. A class which is not an interface and is not static gets an outer link
+ * (@see outerDefs)
+ * 2. A mixin which is not also an interface gets a mixin constructor
+ * (@see mixinConstructorDef)
+ * 3. Constructor bodies are augmented by calls to supermixin constructors
+ * (@see addMixinConstructorCalls)
+ * 4. A constructor of a class with an outer link gets an outer parameter.
+ * 5. A reference C.this where C refers to an outer class is replaced by a selection
+ * this.$outer ... .$outer (@see outerPath)
+ * 6. A reference C.super.M where C refers to an outer class and M is a term member of C
+ * is replaced by a selection
+ * this.$outer ... .$outer.M$super
+ * where M$super is the super accessor symbol of M (@see superAccessor).
+ * 7. A call to a constructor Q.<init>(args) or Q.$init$(args) where Q != this and
+ * the constructor belongs to a non-static class is augmented by an outer argument.
+ * E.g. Q.<init>(args, OUTER) where OUTER is the qualifier corresponding to the
+ * singleton type Q.
+ * 8. A call to a constructor this.<init>(args) in a secondary constructor
+ * is augmented to this.<init>(args, OUTER) where OUTER is the last parameter
+ * of the secondary constructor.
+ */
+ private val firstTransformer = new Transformer {
+
+ var localTyper: analyzer.Typer = typer;
+
+ /** The directly enclosing outer parameter, if we are in a constructor
+ */
+ var outerParam: Symbol = NoSymbol;
+
+ /** The first outer selection from currently transformed tree
+ */
+ def outerValue: Tree =
+ if (outerParam != NoSymbol) gen.Ident(outerParam)
+ else outerSelect(gen.This(currentOwner.enclClass));
+
+ /** The two definitions
+ * val outer : C.this.type _;
+ * def outer(): C.this.type = outer ;
+ * Here, C is the class enclosing the class `clazz' containing the two definitions.
+ */
+ def outerDefs(clazz: Symbol): List[Tree] = {
+ val outerVal = clazz.info.decl(nme.LOCAL_NAME(nme.OUTER));
+ val outerDef = clazz.info.decl(nme.OUTER);
+ List(
+ localTyper.typed {
+ atPos(clazz.pos) {
+ ValDef(outerVal, EmptyTree)
+ }
+ },
+ localTyper.typed {
+ atPos(clazz.pos) {
+ DefDef(outerDef, vparamss => Select(This(clazz), outerVal))
+ }
+ })
+ }
+
+ /** The mixin constructor definition
+ * def $init$(): Unit = ()
+ */
+ def mixinConstructorDef(clazz: Symbol): Tree = localTyper.typed {
+ DefDef(clazz.mixinConstructor, vparamss => Literal(()))
+ }
+
+ /** Add calls to supermixin constructors
+ * super[mix].$init$()
+ * to `tree'. `tree' which is assumed to be the body of a constructor of class `clazz'.
+ */
+ def addMixinConstructorCalls(tree: Tree, clazz: Symbol): Tree = {
+ def mixinConstructorCall(mixin: Symbol): Tree =
+ atPos(tree.pos) {
+ Apply(
+ localTyper.typedOperator {
+ Select(Super(clazz, mixin.name), mixin.mixinConstructor)
+ },
+ List()) setType UnitClass.tpe; // don't type this with typed(...),
+ // as constructor arguments might be missing
+ }
+ val mixinConstructorCalls =
+ for (val mixin <- clazz.info.parents.tail; !(mixin.symbol hasFlag INTERFACE)) yield
+ mixinConstructorCall(mixin.symbol);
+ tree match {
+ case Block(supercall :: stats, expr) =>
+ assert(supercall match {
+ case Apply(Select(Super(_, _), _), _) => true
+ case _ => false
+ });
+ copy.Block(tree, supercall :: mixinConstructorCalls ::: stats, expr);
+ case Block(_, _) =>
+ assert(false, tree); tree
+ case expr =>
+ Block(mixinConstructorCalls, expr) setType expr.tpe
+ }
+ }
+
+ /** The first-step transformation method */
+ override def transform(tree: Tree): Tree = {
+ try {
+ val savedOuterParam = outerParam;
+ val sym = tree.symbol;
+ val tree1 = tree match {
+ case Template(parents, decls) =>
+ val savedLocalTyper = localTyper;
+ outerParam = NoSymbol;
+ localTyper = localTyper.atOwner(tree, currentOwner);
+ var decls1 = decls;
+ if (!(currentOwner hasFlag INTERFACE)) {
+ if (!currentOwner.isStatic)
+ decls1 = decls1 ::: outerDefs(currentOwner); // (1)
+ if (currentOwner.isTrait)
+ decls1 = decls1 ::: List(mixinConstructorDef(currentOwner)) // (2)
+ }
+ localTyper = savedLocalTyper;
+ copy.Template(tree, parents, decls1);
+ case constrDef @ DefDef(mods, name, tparams, vparamss, tpt, rhs)
+ if (sym.isConstructor || sym.isMixinConstructor) =>
+ val vparamss1 =
+ if (sym.owner.isStatic) vparamss
+ else { // (4)
+ val outerField = sym.owner.info.decl(nme.LOCAL_NAME(nme.OUTER));
+ outerParam = sym.newValueParameter(sym.pos, nme.OUTER) setInfo outerField.info;
+ List(vparamss.head ::: List(ValDef(outerParam, EmptyTree)))
+ }
+ val rhs1 =
+ if (sym.isPrimaryConstructor || sym.isMixinConstructor)
+ addMixinConstructorCalls(rhs, sym.owner); // (3)
+ else rhs;
+ copy.DefDef(tree, mods, name, tparams, vparamss1, tpt, rhs1);
+ case This(qual) =>
+ if (sym == currentOwner.enclClass || sym.isStatic) tree
+ else atPos(tree.pos)(outerPath(outerValue, sym)) // (5)
+ case Select(qual @ Super(_, mix), name) =>
+ val qsym = qual.symbol;
+ if (!needSuperAccessors || tree.symbol.isType || qsym == currentOwner.enclClass)
+ tree
+ else atPos(tree.pos) { // (6)
+ val accessor = superAccessor(qsym, tree.symbol, mix);
+ Select(if (qsym.isStatic) This(qsym) else outerPath(outerValue, qsym), accessor)
+ setType accessor.tpe
+ }
+ case Apply(sel @ Select(qual, name), args)
+ if ((name == nme.CONSTRUCTOR || name == nme.MIXIN_CONSTRUCTOR)
+ && !sel.symbol.owner.isStatic) =>
+ val outerVal =
+ if (qual.isInstanceOf[This]) { assert(outerParam != NoSymbol); outerValue } // (8)
+ else gen.mkQualifier(qual.tpe.prefix); // (7)
+ copy.Apply(tree, sel, args ::: List(outerVal))
+ case _ =>
+ tree
+ }
+ val result = super.transform(tree1);
+ outerParam = savedOuterParam;
+ result
+ } catch {//debug
+ case ex: Throwable =>
+ System.out.println("exception when transforming " + tree);
+ throw ex
+ }
+ }
+ }
+
+ /** The second step performs the following transformations:
+ * 1. Add definitions of superaccessors to the members of a class
+ * (@see makeSuperAccessorDefs)
+ * 2. Remove private modifiers from members M of mixins T that are accessed with a qualifier
+ * different from T.this. (@see makeNotPrivate)
+ * 3. Remove `private' modifier from class members M that are accessed from an inner class.
+ * 4. Remove `protected' modifier from class members M that are accessed
+ * without a super qualifier accessed from an inner class. (@see makeNotPrivate)
+ * 5. Remove `private' and `protected' modifiers from type symbols
+ */
+ private val secondTransformer = new Transformer {
+
+ /** Add a definition for each super accessor in `clazz':
+ * def NAME$super$MIX(args) = super[MIX].NAME(args)
+ */
+ def makeSuperAccessorDefs(clazz: Symbol, typer: analyzer.Typer): List[Tree] =
+ (for (val Pair(Triple(owner, accessed, mix), accessor) <- superAccessors.elements;
+ owner == clazz) yield
+ typer.typed {
+ atPos(clazz.pos) {
+ DefDef(accessor, vparamss =>
+ Apply(Select(Super(clazz, mix), accessed), vparamss.head map Ident))
+ }
+ }).toList;
+
+ /** Remove private modifier from symbol `sym's definition. If `sym' is a
+ * term symbol rename it by appending $$<fully-qualified-name-of-enclosing-class
+ * to avoid name clashes.
+ */
+ def makeNotPrivate(sym: Symbol): unit =
+ if (sym hasFlag PRIVATE) {
+ if (sym.isTerm)
+ sym.name = newTermName(
+ sym.name.toString() + "$$" + sym.owner.enclClass.fullNameString('$'));
+ sym setFlag notPRIVATE;
+ }
+
+ /** The second-step transformation method */
+ override def transform(tree: Tree): Tree = {
+ val sym = tree.symbol;
+ val tree1 = super.transform(tree);
+ tree1 match {
+ case Template(parents, stats) => // (1)
+ val accessors = makeSuperAccessorDefs(sym.owner, typer.atOwner(tree1, currentOwner));
+ if (accessors.isEmpty) tree1
+ else copy.Template(tree1, parents, stats ::: accessors)
+ case Select(qual, name) =>
+ if ((sym hasFlag PRIVATE) &&
+ ((sym.owner.isTrait && qual.tpe != sym.owner.thisType) || // (2)
+ currentOwner.enclClass != sym.owner)) // (3)
+ makeNotPrivate(sym)
+ else if ((sym hasFlag PROTECTED) &&
+ !(qual.isInstanceOf[Super] ||
+ (qual.tpe.widen.symbol isSubClass currentOwner.enclClass)))
+ sym setFlag notPROTECTED;
+ tree1
+ case _ =>
+ if (sym != null && sym.isType) {
+ if (sym hasFlag PRIVATE) sym setFlag notPRIVATE;
+ if (sym hasFlag PROTECTED) sym setFlag notPROTECTED;
+ }
+ tree1
+ }
+ }
+ }
+
+ /** The main transformation method:
+ * First, perform step 1 on whole tree of compilation unit.
+ * Then, perform step 2 on resulting tree
+ */
+ override def transform(tree: Tree) =
+ atPhase(phase.next) {
+ secondTransformer.transform(firstTransformer.transform(tree))
+ }
+ }
+}
+
+