/* NSC -- new scala compiler * Copyright 2005 LAMP/EPFL * @author */ // $Id$ package scala.tools.nsc.typechecker; import scala.collection.mutable.ListBuffer; import nsc.symtab.Flags._; /** This phase adds super accessors for all super calls that * either appear in a trait or have as a target a member of some outer class. * It also replaces references to parameter accessors with aliases by super * references to these aliases. * The phase also checks that symbols accessed from super are not abstract, * or are overridden by an abstract override. * Finally, the phase also mangles the names of class-members which are private * up to an enclosing non-package class, in order to avoid overriding conflicts. */ abstract class SuperAccessors extends transform.Transform { // inherits abstract value `global' and class `Phase' from Transform import global._; import posAssigner.atPos; import typer.typed; /** the following two members override abstract members in Transform */ val phaseName: String = "superaccessors"; protected def newTransformer(unit: CompilationUnit): Transformer = new SuperAccTransformer(unit); class SuperAccTransformer(unit: CompilationUnit) extends Transformer { private var validCurrentOwner = true; private var accDefs: List[Pair[Symbol, ListBuffer[Tree]]] = List(); private def accDefBuf(clazz: Symbol) = accDefs.dropWhile(._1.!=(clazz)).head._2; private def transformArgs(args: List[Tree], formals: List[Type]) = { if (!formals.isEmpty && formals.last.symbol == definitions.ByNameParamClass) ((args take (formals.length - 1) map transform) ::: withInvalidOwner { args drop (formals.length - 1) map transform }) else args map transform } override def transform(tree: Tree): Tree = tree match { case ClassDef(_, _, _, _, _) => val decls = tree.symbol.info.decls for (val sym <- decls.toList) { if (sym.privateWithin.isClass && !sym.privateWithin.isModuleClass && !sym.hasFlag(EXPANDEDNAME)) { decls.unlink(sym) sym.expandName(sym.privateWithin) decls.enter(sym) } } super.transform(tree) case Template(parents, body) => val ownAccDefs = new ListBuffer[Tree]; accDefs = Pair(currentOwner, ownAccDefs) :: accDefs; val body1 = transformTrees(body); accDefs = accDefs.tail; copy.Template(tree, parents, ownAccDefs.toList ::: body1); case Select(qual @ This(_), name) => val sym = tree.symbol; if ((sym hasFlag PARAMACCESSOR) && (sym.alias != NoSymbol)) { val result = typed { Select( Super(qual.symbol, nme.EMPTY.toTypeName/*qual.symbol.info.parents.head.symbol.name*/) setPos qual.pos, sym.alias) setPos tree.pos } if (settings.debug.value) System.out.println("alias replacement: " + tree + " ==> " + result);//debug transform(result) } else tree case Select(sup @ Super(_, mix), name) => val sym = tree.symbol; val clazz = sup.symbol; if (sym hasFlag DEFERRED) { val member = sym.overridingSymbol(clazz); if (mix != nme.EMPTY.toTypeName || member == NoSymbol || !((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz))) unit.error(tree.pos, ""+sym+sym.locationString+" is accessed from super. It may not be abstract "+ "unless it is overridden by a member declared `abstract' and `override'"); } if (tree.isTerm && mix == nme.EMPTY.toTypeName && (clazz.isTrait || clazz != currentOwner.enclClass || !validCurrentOwner)) { val supername = nme.superName(sym.name); var superAcc = clazz.info.decl(supername).suchThat(.alias.==(sym)); if (superAcc == NoSymbol) { if (settings.debug.value) log("add super acc " + sym + sym.locationString + " to `" + clazz);//debug superAcc = clazz.newMethod(tree.pos, supername) .setFlag(SUPERACCESSOR | PRIVATE) .setInfo(clazz.thisType.memberType(sym)) .setAlias(sym) clazz.info.decls enter superAcc; accDefBuf(clazz) += typed(DefDef(superAcc, vparamss => EmptyTree)) } atPos(sup.pos) { Select(gen.mkAttributedThis(clazz), superAcc) setType tree.tpe; } } else tree case Apply(fn, args) => copy.Apply(tree, transform(fn), transformArgs(args, fn.tpe.paramTypes)) case Function(vparams, body) => withInvalidOwner { copy.Function(tree, vparams, transform(body)) } case _ => super.transform(tree) } override def atOwner[A](owner: Symbol)(trans: => A): A = { if (owner.isClass) validCurrentOwner = true; super.atOwner(owner)(trans) } private def withInvalidOwner[A](trans: => A): A = { val prevValidCurrentOwner = validCurrentOwner; validCurrentOwner = false; val result = trans; validCurrentOwner = prevValidCurrentOwner; result } } }