scala.tools.nsc.transform.AddInterfaces.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.apache.servicemix.bundles.scala-compiler
Show all versions of org.apache.servicemix.bundles.scala-compiler
This OSGi bundle wraps ${pkgArtifactId} ${pkgVersion} jar file.
/* NSC -- new Scala compiler
* Copyright 2005-2011 LAMP/EPFL
* @author Martin Odersky
*/
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._ // the global environment
import definitions._ // standard classes and methods
/**
* The phase sets lateINTERFACE
for non-interface traits
* that now become interfaces.
*
*
* It sets lateDEFERRED
for formerly concrete methods in
* such traits.
*
*/
override def phaseNewFlags: Long = lateDEFERRED | lateINTERFACE
/** Type reference after erasure; to be defined in subclass
* Erasure
.
*/
def erasedTypeRef(sym: Symbol): Type
/** Erasure type-map; to be defined in subclass
* Erasure
.
*/
def erasure: TypeMap
/** A lazily constructed map that associates every non-interface trait with
* its implementation class.
*/
private val implClassMap = new mutable.HashMap[Symbol, Symbol]
/** A lazily constructed map that associates every concrete method in a non-interface
* trait that's currently compiled with its corresponding method in the trait's
* implementation class.
*/
private val implMethodMap = new mutable.HashMap[Symbol, Symbol]
override def newPhase(prev: scala.tools.nsc.Phase): StdPhase = {
implClassMap.clear()
implMethodMap.clear()
super.newPhase(prev)
}
/** Is given trait member symbol a member of the trait's interface
* after this transform is performed? */
private def isInterfaceMember(sym: Symbol): Boolean = {
sym.isType ||
{ sym.info; // to set lateMETHOD flag if necessary
sym.isMethod &&
!sym.isLabel &&
!sym.isPrivate &&
(!(sym hasFlag BRIDGE) || sym.hasBridgeAnnotation) && // count @_$bridge$_ annotated classes as interface members
!sym.isConstructor &&
!sym.isImplOnly
}
}
/** Does symbol need an implementation method? */
private def needsImplMethod(sym: Symbol): Boolean =
sym.isMethod && isInterfaceMember(sym) &&
(!(sym hasFlag (DEFERRED | SUPERACCESSOR)) || (sym hasFlag lateDEFERRED))
def implClassPhase = currentRun.erasurePhase.next
/** Return the implementation class of a trait; create a new one of one does not yet exist */
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)//debug
impl
}
})
/**
* A lazy type to set the info of an implementation class
* The parents of an implementation class for trait iface
are:
*
*
* - superclass:
Object
* -
* mixin classes: mixin classes of
iface
where every
* non-interface trait is mapped to its implementation class, followed
* by iface
itself.
*
*
*
* The declarations of a mixin class are:
*
*
* -
* for every interface member of
iface
its implementation
* method, if one is needed.
*
* -
* every former member of
iface
that is implementation only
*
*
*/
private class LazyImplClassType(iface: Symbol) extends LazyType {
/** Compute the decls of implementation class implClass
,
* given the decls ifaceDecls
of its interface.
*
* @param implClass ...
* @param ifaceDecls ...
* @return ...
*/
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
// note: OK to destructively modify the owner here,
// because symbol will not be accessible from outside the sourcefile.
// mixin constructors are corrected separately; see TermSymbol.owner
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) }
}
/** If type tp
refers to a non-interface trait, return a
* reference to its implementation class. Otherwise return tp
* itself.
*
* @param tp ...
* @return ...
*/
private def mixinToImplClass(tp: Type): Type =
erasure(
tp match { //@MATN: no normalize needed (comes after erasure)
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) // generate an impl class
}
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))
//if (!clazz.isPackageClass) System.out.println("Decls of "+clazz+" after explicitOuter = " + decls1);//DEBUG
//if ((parents1 eq parents) && (decls1 eq decls)) tp
//else
ClassInfoType(parents1, decls1, clazz)
case _ =>
tp
}
// Tree transformation --------------------------------------------------------------
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
/** Add mixin constructor definition
* def $init$(): Unit = ()
* to `stats' unless there is already one.
*/
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))
}
}
/** Add calls to supermixin constructors
* super[mix].$init$()
* to tree
. tree
which is assumed to be the body
* of a constructor of class clazz
.
*/
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) =>
// needs `hasSymbol' check because `supercall' could be a block (named / default args)
val (presuper, supercall :: rest) = stats span (t => t.hasSymbolWhich(_ hasFlag PRESUPER))
//assert(supercall.symbol.isClassConstructor, supercall)
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 // to force lateDEFERRED flags
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)) // (3)
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 Super(qual, mix) =>
val mix1 = mix
if (mix == tpnme.EMPTY) mix
else {
val ps = atPhase(currentRun.erasurePhase) {
sym.info.parents dropWhile (p => p.symbol.name != mix)
}
assert(!ps.isEmpty, tree);
if (ps.head.symbol.needsImplClass) implClass(ps.head.symbol).name
else mix
}
if (sym.needsImplClass) Super(implClass(sym), mix1) setPos tree.pos
else treeCopy.Super(tree, qual, mix1)
*/
case _ =>
tree
}
super.transform(tree1)
}
}
}
/*
val ensureNoEscapes = new TypeTraverser {
def ensureNoEscape(sym: Symbol) {
if (sym.hasFlag(PRIVATE)) {
var o = currentOwner;
while (o != NoSymbol && o != sym.owner && !o.isLocal && !o.hasFlag(PRIVATE))
o = o.owner
if (o == sym.owner) sym.makeNotPrivate(base);
}
}
def traverse(t: Type): TypeTraverser = {
t match {
case TypeRef(qual, sym, args) =>
ensureNoEscape(sym)
mapOver(t)
case ClassInfoType(parents, decls, clazz) =>
parents foreach { p => traverse; () }
traverse(t.typeOfThis)
case _ =>
mapOver(t)
}
this
}
}
*/
© 2015 - 2025 Weber Informatics LLC | Privacy Policy