package scala.tools.nsc
package transform
import symtab._
import Flags._
import scala.collection.{ mutable, immutable }
import collection.mutable.ListBuffer
abstract class AddInterfaces extends InfoTransform {
import global._
import definitions._
override def phaseNewFlags: Long = lateDEFERRED | lateINTERFACE
def erasedTypeRef(sym: Symbol): Type
def erasure: TypeMap
private val implClassMap = new mutable.HashMap[Symbol, Symbol]
private val implMethodMap = new mutable.HashMap[Symbol, Symbol]
override def newPhase(prev: scala.tools.nsc.Phase): StdPhase = {
implClassMap.clear()
implMethodMap.clear()
super.newPhase(prev)
}
private def isInterfaceMember(sym: Symbol): Boolean = {
sym.isType ||
{ sym.info;
sym.isMethod &&
!sym.isLabel &&
!sym.isPrivate &&
(!(sym hasFlag BRIDGE) || sym.hasBridgeAnnotation) &&
!sym.isConstructor &&
!sym.isImplOnly
}
}
private def needsImplMethod(sym: Symbol): Boolean =
sym.isMethod && isInterfaceMember(sym) &&
(!(sym hasFlag (DEFERRED | SUPERACCESSOR)) || (sym hasFlag lateDEFERRED))
def implClassPhase = currentRun.erasurePhase.next
def implClass(iface: Symbol): Symbol = implClassMap.getOrElse(iface, {
atPhase(implClassPhase) {
val implName = nme.implClassName(iface.name)
var impl = if (iface.owner.isClass) iface.owner.info.decl(implName) else NoSymbol
if (impl != NoSymbol && settings.XO.value) {
log("unlinking impl class " + impl)
iface.owner.info.decls.unlink(impl)
impl = NoSymbol
}
if (impl == NoSymbol) {
impl = iface.cloneSymbolImpl(iface.owner)
impl.name = implName
impl.sourceFile = iface.sourceFile
if (iface.owner.isClass)
iface.owner.info.decls enter impl
}
if (currentRun.compiles(iface)) currentRun.symSource(impl) = iface.sourceFile
impl setPos iface.pos
impl.flags = iface.flags & ~(INTERFACE | lateINTERFACE) | IMPLCLASS
impl setInfo new LazyImplClassType(iface)
implClassMap(iface) = impl
if (settings.debug.value) log("generating impl class " + impl + " in " + iface.owner)
impl
}
})
private class LazyImplClassType(iface: Symbol) extends LazyType {
private def implDecls(implClass: Symbol, ifaceDecls: Scope): Scope = {
val decls = new Scope
if ((ifaceDecls lookup nme.MIXIN_CONSTRUCTOR) == NoSymbol)
decls enter (implClass.newMethod(implClass.pos, nme.MIXIN_CONSTRUCTOR)
setInfo MethodType(List(), UnitClass.tpe))
for (sym <- ifaceDecls.iterator) {
if (isInterfaceMember(sym)) {
if (needsImplMethod(sym)) {
val impl = sym.cloneSymbol(implClass).resetFlag(lateDEFERRED)
if (currentRun.compiles(implClass)) implMethodMap(sym) = impl
decls enter impl
sym setFlag lateDEFERRED
}
} else {
sym.owner = implClass
decls enter sym
}
}
decls
}
override def complete(sym: Symbol) {
def implType(tp: Type): Type = tp match {
case ClassInfoType(parents, decls, _) =>
assert(phase == implClassPhase)
ClassInfoType(
ObjectClass.tpe :: (parents.tail map mixinToImplClass filter (_.typeSymbol != ObjectClass))
::: List(iface.tpe),
implDecls(sym, decls),
sym)
case PolyType(tparams, restpe) =>
implType(restpe)
}
sym.setInfo(implType(atPhase(currentRun.erasurePhase)(iface.info)))
}
override def load(clazz: Symbol) { complete(clazz) }
}
private def mixinToImplClass(tp: Type): Type =
erasure(
tp match {
case TypeRef(pre, sym, args) if (sym.needsImplClass) =>
typeRef(pre, implClass(sym), args)
case _ =>
tp
})
def transformMixinInfo(tp: Type): Type = tp match {
case ClassInfoType(parents, decls, clazz) =>
if (clazz.needsImplClass) {
clazz setFlag lateINTERFACE
implClass(clazz)
}
val parents1 = parents match {
case Nil => Nil
case hd :: tl =>
assert(!hd.typeSymbol.isTrait, clazz)
if (clazz.isTrait) erasedTypeRef(ObjectClass) :: tl
else parents
}
val decls1 = decls filter (sym =>
if (clazz.isInterface) isInterfaceMember(sym)
else (!sym.isType || sym.isClass))
ClassInfoType(parents1, decls1, clazz)
case _ =>
tp
}
private class ChangeOwnerAndReturnTraverser(oldowner: Symbol, newowner: Symbol)
extends ChangeOwnerTraverser(oldowner, newowner) {
override def traverse(tree: Tree) {
tree match {
case Return(expr) =>
if (tree.symbol == oldowner) tree.symbol = newowner
case _ =>
}
super.traverse(tree)
}
}
private def ifaceMemberDef(tree: Tree): Tree =
if (!tree.isDef || !isInterfaceMember(tree.symbol)) EmptyTree
else if (needsImplMethod(tree.symbol)) DefDef(tree.symbol, EmptyTree)
else tree
private def ifaceTemplate(templ: Template): Template =
treeCopy.Template(templ, templ.parents, emptyValDef, templ.body map ifaceMemberDef)
private def implMethodDef(tree: Tree, ifaceMethod: Symbol): Tree =
implMethodMap.get(ifaceMethod) match {
case Some(implMethod) =>
tree.symbol = implMethod
new ChangeOwnerAndReturnTraverser(ifaceMethod, implMethod)(tree)
case None =>
abort("implMethod missing for " + ifaceMethod)
}
private def implMemberDef(tree: Tree): Tree =
if (!tree.isDef || !isInterfaceMember(tree.symbol)) tree
else if (needsImplMethod(tree.symbol)) implMethodDef(tree, tree.symbol)
else EmptyTree
private def addMixinConstructorDef(clazz: Symbol, stats: List[Tree]): List[Tree] =
if (treeInfo.firstConstructor(stats) != EmptyTree) stats
else DefDef(clazz.primaryConstructor, Block(List(), Literal(()))) :: stats
private def implTemplate(clazz: Symbol, templ: Template): Template = atPos(templ.pos) {
val templ1 = atPos(templ.pos) {
Template(templ.parents, emptyValDef,
addMixinConstructorDef(clazz, templ.body map implMemberDef))
.setSymbol(clazz.newLocalDummy(templ.pos))
}
new ChangeOwnerTraverser(templ.symbol.owner, clazz)(
new ChangeOwnerTraverser(templ.symbol, templ1.symbol)(templ1))
}
def implClassDefs(trees: List[Tree]): List[Tree] = {
trees collect {
case cd: ClassDef if cd.symbol.needsImplClass =>
val clazz = implClass(cd.symbol).initialize
ClassDef(clazz, implTemplate(clazz, cd.impl))
}
}
private def addMixinConstructorCalls(tree: Tree, clazz: Symbol): Tree = {
def mixinConstructorCall(impl: Symbol): Tree = atPos(tree.pos) {
Apply(Select(This(clazz), impl.primaryConstructor), List())
}
val mixinConstructorCalls: List[Tree] = {
for (mc <- clazz.mixinClasses.reverse
if mc.hasFlag(lateINTERFACE) && mc != ScalaObjectClass)
yield mixinConstructorCall(implClass(mc))
}
(tree: @unchecked) match {
case Block(stats, expr) =>
val (presuper, supercall :: rest) = stats span (t => t.hasSymbolWhich(_ hasFlag PRESUPER))
treeCopy.Block(tree, presuper ::: (supercall :: mixinConstructorCalls ::: rest), expr)
}
}
protected val mixinTransformer = new Transformer {
override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] =
(super.transformStats(stats, exprOwner) :::
super.transformStats(implClassDefs(stats), exprOwner))
override def transform(tree: Tree): Tree = {
val sym = tree.symbol
val tree1 = tree match {
case ClassDef(mods, name, tparams, impl) if (sym.needsImplClass) =>
implClass(sym).initialize
treeCopy.ClassDef(tree, mods | INTERFACE, name, tparams, ifaceTemplate(impl))
case DefDef(mods, name, tparams, vparamss, tpt, rhs)
if (sym.isClassConstructor && sym.isPrimaryConstructor && sym.owner != ArrayClass) =>
treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt,
addMixinConstructorCalls(rhs, sym.owner))
case Template(parents, self, body) =>
val parents1 = sym.owner.info.parents map (t => TypeTree(t) setPos tree.pos)
treeCopy.Template(tree, parents1, emptyValDef, body)
case This(_) =>
if (sym.needsImplClass) {
val impl = implClass(sym)
var owner = currentOwner
while (owner != sym && owner != impl) owner = owner.owner;
if (owner == impl) This(impl) setPos tree.pos
else tree
} else tree
case _ =>
tree
}
super.transform(tree1)
}
}
}
<iframe src="https://xuwei-k.github.io/scala-compiler-sxr/scala-compiler-2.9.1/scala/tools/nsc/transform/AddInterfaces.scala.html" width="1280" height="720" frameborder="0"> </iframe>