/* NSC -- new scala compiler * Copyright 2005 LAMP/EPFL * @author */ // $Id$ package scala.tools.nsc.transform; import symtab._; import Flags._; import util.{ListBuffer} import scala.tools.util.Position; abstract class Mixin extends InfoTransform { import global._; import definitions._; import posAssigner.atPos; /** the following two members override abstract members in Transform */ val phaseName: String = "mixin"; override def phaseNewFlags: long = lateMODULE | notABSTRACT; private def isForwarded(sym: Symbol) = sym.owner.isImplClass && sym.isMethod && !(sym hasFlag (ACCESSOR | SUPERACCESSOR)); private def isStatic(sym: Symbol) = isForwarded(sym) && (sym.hasFlag(PRIVATE) || sym.isConstructor); private def toInterface(tp: Type): Type = tp.symbol.toInterface.tpe; private def rebindSuper(base: Symbol, member: Symbol, prevowner: Symbol): Symbol = atPhase(currentRun.refchecksPhase) { var bcs = base.info.baseClasses.dropWhile(prevowner !=).tail; assert(!bcs.isEmpty/*, "" + prevowner + " " + base.info.baseClasses*/);//DEBUG var sym: Symbol = NoSymbol; if (settings.debug.value) log("starting rebindsuper " + base + " " + member + ":" + member.tpe + " " + prevowner + " " + base.info.baseClasses); while (!bcs.isEmpty && sym == NoSymbol) { if (settings.debug.value) { val other = bcs.head.info.nonPrivateDecl(member.name); log("rebindsuper " + bcs.head + " " + other + " " + other.tpe + " " + other.hasFlag(DEFERRED)); } sym = member.overridingSymbol(bcs.head).suchThat(sym => !sym.hasFlag(DEFERRED)); bcs = bcs.tail } assert(sym != NoSymbol, member); sym } private def implClass(iface: Symbol): Symbol = erasure.implClass(iface); def addMember(clazz: Symbol, member: Symbol): Symbol = { if (settings.debug.value) log("new member of " + clazz + ":" + member.defString);//debug clazz.info.decls enter member; member } def addLateInterfaceMembers(clazz: Symbol) = if (!(clazz hasFlag MIXEDIN)) { clazz setFlag MIXEDIN; def newGetter(field: Symbol): Symbol = clazz.newMethod(field.pos, nme.getterName(field.name)) setFlag (field.flags & ~(PRIVATE | LOCAL) | ACCESSOR | DEFERRED | SYNTHETIC) setInfo MethodType(List(), field.info); def newSetter(field: Symbol): Symbol = clazz.newMethod(field.pos, nme.getterToSetter(nme.getterName(field.name))) setFlag (field.flags & ~(PRIVATE | LOCAL) | ACCESSOR | DEFERRED | SYNTHETIC) setInfo MethodType(List(field.info), UnitClass.tpe); clazz.info; val impl = implClass(clazz); assert(impl != NoSymbol); for (val member <- impl.info.decls.toList) { if (!member.isMethod && !member.isModule && !member.isModuleVar) { assert(member.isTerm && !member.hasFlag(DEFERRED), member); if (member.getter(impl) hasFlag PRIVATE) member.makeNotPrivate(clazz); var getter = member.getter(clazz); if (getter == NoSymbol) getter = addMember(clazz, newGetter(member)); else getter setFlag (member getFlag MUTABLE); if (!member.tpe.isInstanceOf[ConstantType]) { var setter = member.setter(clazz); if (setter == NoSymbol) setter = addMember(clazz, newSetter(member)); } } else if ((member hasFlag (LIFTED | BRIDGE)) && !(member hasFlag PRIVATE)) { member.expandName(clazz); addMember(clazz, member.cloneSymbol(clazz)); } } if (settings.debug.value) log("new defs of " + clazz + " = " + clazz.info.decls); } def addMixedinMembers(clazz: Symbol): unit = if (!(clazz hasFlag MIXEDIN) && (clazz != ObjectClass)) { assert(!clazz.isTrait, clazz); clazz setFlag MIXEDIN; assert(!clazz.info.parents.isEmpty, clazz); val superclazz = clazz.info.parents.head.symbol; addMixedinMembers(superclazz); for (val bc <- clazz.info.baseClasses.tail.takeWhile(superclazz !=)) if (bc.hasFlag(lateINTERFACE)) addLateInterfaceMembers(bc); for (val bc <- clazz.info.baseClasses.tail.takeWhile(superclazz !=)) { if (bc.isImplClass) { for (val member <- bc.info.decls.toList) { if (isForwarded(member) && !isStatic(member) && (clazz.info.member(member.name).alternatives contains member)) { val member1 = addMember(clazz, member.cloneSymbol(clazz) setFlag MIXEDIN); member1.asInstanceOf[TermSymbol] setAlias member; } } } else if (bc.hasFlag(lateINTERFACE)) { for (val member <- bc.info.decls.toList) { if (member hasFlag ACCESSOR) { val member1 = addMember(clazz, member.cloneSymbol(clazz) setFlag (MIXEDIN | FINAL) resetFlag DEFERRED); if (!member.isSetter) member.tpe match { case MethodType(List(), ConstantType(_)) => ; case _ => addMember(clazz, clazz.newValue(member.pos, nme.getterToLocal(member.name)) setFlag (LOCAL | PRIVATE | MIXEDIN | member.getFlag(MUTABLE)) setInfo member.tpe.resultType) } } else if (member hasFlag SUPERACCESSOR) { val member1 = addMember(clazz, member.cloneSymbol(clazz)) setFlag MIXEDIN; assert(member1.alias != NoSymbol, member1); val alias1 = rebindSuper(clazz, member.alias, bc); member1.asInstanceOf[TermSymbol] setAlias alias1; } else if (member.isMethod && member.isModule && !(member hasFlag (LIFTED | BRIDGE))) { addMember(clazz, member.cloneSymbol(clazz) setFlag MIXEDIN) } } } } if (settings.debug.value) log("new defs of " + clazz + " = " + clazz.info.decls); } override def transformInfo(sym: Symbol, tp: Type): Type = tp match { case ClassInfoType(parents, decls, clazz) => assert(clazz.info eq tp, tp); assert(sym == clazz, tp); var parents1 = parents; var decls1 = decls; if (!clazz.isPackageClass) { atPhase(phase.next)(clazz.owner.info); if (clazz.isImplClass) { clazz setFlag lateMODULE; var sourceModule = clazz.owner.info.decls.lookup(sym.name.toTermName); if (sourceModule != NoSymbol) { sourceModule setPos sym.pos; sourceModule.flags = MODULE | FINAL; } else { sourceModule = clazz.owner.newModule( sym.pos, sym.name.toTermName, sym.asInstanceOf[ClassSymbol]); clazz.owner.info.decls enter sourceModule } sourceModule setInfo sym.tpe; assert(clazz.sourceModule != NoSymbol);//debug parents1 = List(); decls1 = new Scope(decls.toList filter isForwarded) } else if (!parents.isEmpty) { parents1 = parents.head :: (parents.tail map toInterface); } } //decls1 = atPhase(phase.next)(new Scope(decls1.toList));//debug if ((parents1 eq parents) && (decls1 eq decls)) tp else ClassInfoType(parents1, decls1, clazz); case MethodType(formals, restp) => if (isForwarded(sym)) MethodType(toInterface(sym.owner.typeOfThis) :: formals, restp) else tp case _ => tp } protected def newTransformer(unit: CompilationUnit): Transformer = new MixinTransformer; class MixinTransformer extends Transformer { private var self: Symbol = _; private var localTyper: analyzer.Typer = _; private var enclInterface: Symbol = _; private def preTransform(tree: Tree): Tree = { val sym = tree.symbol; tree match { case Template(parents, body) => localTyper = typer.atOwner(tree, currentOwner); atPhase(phase.next)(currentOwner.owner.info);//needed? if (!currentOwner.isTrait) addMixedinMembers(currentOwner) else if (currentOwner hasFlag lateINTERFACE) addLateInterfaceMembers(currentOwner); tree case DefDef(mods, name, tparams, List(vparams), tpt, rhs) if currentOwner.isImplClass => if (isForwarded(sym)) { sym setFlag notOVERRIDE; self = sym.newValue(sym.pos, nme.SELF) setFlag (PARAM | SYNTHETIC) setInfo toInterface(currentOwner.typeOfThis); enclInterface = currentOwner.toInterface; val selfdef = ValDef(self) setType NoType; copy.DefDef(tree, mods, name, tparams, List(selfdef :: vparams), tpt, rhs) } else { EmptyTree } case ValDef(_, _, _, _) if (currentOwner.isImplClass) => EmptyTree case _ => tree } } private def selfRef(pos: int) = gen.Ident(self) setPos pos; private def staticRef(sym: Symbol) = { sym.owner.info; sym.owner.owner.info; if (sym.owner.sourceModule == NoSymbol) { assert(false, "" + sym + " in " + sym.owner + " in " + sym.owner.owner + " " + sym.owner.owner.info.decls.toList);//debug } Select(gen.mkRef(sym.owner.sourceModule), sym); } private def addNewDefs(clazz: Symbol, stats: List[Tree]): List[Tree] = { val newDefs = new ListBuffer[Tree]; def addDef(pos: int, tree: Tree): unit = { if (settings.debug.value) log("add new def to " + clazz + ": " + tree); newDefs += localTyper.typed { atPos(pos) { tree } } } def position(sym: Symbol) = if (sym.pos == Position.NOPOS) clazz.pos else sym.pos; def addDefDef(sym: Symbol, rhs: List[Symbol] => Tree): unit = addDef(position(sym), DefDef(sym, vparamss => rhs(vparamss.head))); def completeSuperAccessor(stat: Tree) = stat match { case DefDef(mods, name, tparams, List(vparams), tpt, EmptyTree) if (stat.symbol hasFlag SUPERACCESSOR) => assert(stat.symbol hasFlag MIXEDIN, stat); val rhs0 = Apply(Select(Super(clazz, nme.EMPTY.toTypeName), stat.symbol.alias), vparams map (vparam => Ident(vparam.symbol))); if (settings.debug.value) log("complete super acc " + stat.symbol + stat.symbol.locationString + " " + rhs0 + " " + stat.symbol.alias + stat.symbol.alias.locationString);//debug val rhs1 = postTransform(localTyper.typed(atPos(stat.pos)(rhs0))); copy.DefDef(stat, mods, name, tparams, List(vparams), tpt, rhs1) case _ => stat } var stats1 = stats; if (clazz hasFlag lateINTERFACE) { for (val sym <- clazz.info.decls.toList) { if ((sym hasFlag SYNTHETIC) && (sym hasFlag ACCESSOR)) addDefDef(sym, vparamss => EmptyTree) } if (newDefs.hasNext) stats1 = stats1 ::: newDefs.toList; } else if (!clazz.isTrait) { for (val sym <- clazz.info.decls.toList) { if (sym hasFlag MIXEDIN) { if (sym hasFlag ACCESSOR) { addDefDef(sym, vparams => { val accessedRef = sym.tpe match { case MethodType(List(), ConstantType(c)) => Literal(c) case _ => Select(This(clazz), sym.accessed) } if (sym.isSetter) Assign(accessedRef, Ident(vparams.head)) else accessedRef}) } else if (sym.isModule && !(sym hasFlag LIFTED)) { val vdef = refchecks.newModuleVarDef(sym); addDef(position(sym), vdef); addDef(position(sym), refchecks.newModuleAccessDef(sym, vdef.symbol)); } else if (!sym.isMethod) { addDef(position(sym), ValDef(sym)) } else if (sym hasFlag SUPERACCESSOR) { addDefDef(sym, vparams => EmptyTree) } else { assert(sym.alias != NoSymbol, sym); addDefDef(sym, vparams => Apply(staticRef(sym.alias), gen.This(clazz) :: (vparams map Ident))) } } } if (newDefs.hasNext) stats1 = stats1 ::: newDefs.toList; } if (clazz.isTrait) stats1 else stats1 map completeSuperAccessor; } private def postTransform(tree: Tree): Tree = { val sym = tree.symbol; tree match { case Template(parents, body) => val parents1 = currentOwner.info.parents map (t => TypeTree(t) setPos tree.pos); val body1 = addNewDefs(currentOwner, body); copy.Template(tree, parents1, body1) case Apply(Select(qual, _), args) => assert(sym != NoSymbol, tree);//debug if (isStatic(sym)) { assert(sym.isConstructor || currentOwner.enclClass.isImplClass, tree); localTyper.typed { atPos(tree.pos) { Apply(staticRef(sym), qual :: args) } } } else if (qual.isInstanceOf[Super] && (sym.owner hasFlag lateINTERFACE)) { val sym1 = atPhase(phase.prev)(sym.overridingSymbol(sym.owner.implClass)); if (sym1 == NoSymbol) assert(false, "" + sym + " " + sym.owner + " " + sym.owner.implClass + " " + sym.owner.owner + atPhase(phase.prev)(sym.owner.owner.info.decls.toList));//debug localTyper.typed { atPos(tree.pos) { Apply(staticRef(sym1), gen.This(currentOwner.enclClass) :: args) } } } else { tree } case This(_) if tree.symbol.isImplClass => assert(tree.symbol == currentOwner.enclClass, "" + tree + " " + tree.symbol + " " + currentOwner.enclClass); selfRef(tree.pos) case Select(qual @ Super(_, mix), name) => if (currentOwner.enclClass.isImplClass) { if (mix == nme.EMPTY.toTypeName) { val superAccName = enclInterface.expandedName(nme.superName(sym.name)); val superAcc = enclInterface.info.decl(superAccName) suchThat (.alias.==(sym)); assert(superAcc != NoSymbol, tree);//debug localTyper.typedOperator { atPos(tree.pos){ Select(selfRef(qual.pos), superAcc) } } } else { copy.Select(tree, selfRef(qual.pos), name) } } else { if (mix == nme.EMPTY.toTypeName) tree else copy.Select(tree, gen.This(currentOwner.enclClass) setPos qual.pos, name) } case Select(qual, name) if sym.owner.isImplClass && !isStatic(sym) => if (sym.isMethod) { assert(sym hasFlag (LIFTED | BRIDGE), sym); val sym1 = enclInterface.info.decl(sym.name); assert(sym1 != NoSymbol, sym); assert(!(sym1 hasFlag OVERLOADED), sym);//debug tree setSymbol sym1 } else { val getter = sym.getter(enclInterface); assert(getter != NoSymbol); localTyper.typed { atPos(tree.pos) { Apply(Select(qual, getter), List()) } } } /* case Ident(_) => if (sym.owner.isClass) { assert(sym.isModuleVar, sym); assert(!sym.owner.isImplClass, sym); atPos(tree.pos) { gen.SelectThis( */ case Assign(Apply(lhs @ Select(qual, _), List()), rhs) => localTyper.typed { atPos(tree.pos) { Apply(Select(qual, lhs.symbol.setter(enclInterface)) setPos lhs.pos, List(rhs)) } } case TypeApply(fn, List(arg)) => if (arg.tpe.symbol.isImplClass) arg.tpe = toInterface(arg.tpe); tree case _ => tree } } override def transform(tree: Tree): Tree = { try { //debug val tree1 = super.transform(preTransform(tree)); atPhase(phase.next)(postTransform(tree1)) } catch { case ex: Throwable => System.out.println("exception when traversing " + tree); throw ex } } } }