alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (AddInterfaces.scala)

This example Scala source code file (AddInterfaces.scala) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Scala tags/keywords

classdef, classinfotype, emptytree, list, list, nosymbol, scope, symbol, symbol, template, tree, tree, type, type

The Scala AddInterfaces.scala source code

/* 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

  /** <p>
   *    The phase sets <code>lateINTERFACE for non-interface traits
   *    that now become interfaces.
   *  </p>
   *  <p>
   *    It sets <code>lateDEFERRED for formerly concrete methods in
   *    such traits.
   *  </p>
   */
  override def phaseNewFlags: Long = lateDEFERRED | lateINTERFACE

  /** Type reference after erasure; to be defined in subclass
   *  <code>Erasure.
   */
  def erasedTypeRef(sym: Symbol): Type

  /** Erasure type-map; to be defined in subclass
   *  <code>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
    }
  })

  /** <p>
   *    A lazy type to set the info of an implementation class 
   *    The parents of an implementation class for trait <code>iface are:
   *  </p>
   *  <ul>
   *    <li>superclass: Object
   *    <li>
   *      mixin classes: mixin classes of <code>iface where every
   *      non-interface trait is mapped to its implementation class, followed
   *      by <code>iface itself.
   *    </li>
   *  </ul>
   *  <p>
   *    The declarations of a mixin class are:
   *  </p>
   *  <ul>
   *    <li>
   *      for every interface member of <code>iface its implementation
   *      method, if one is needed.
   *    </li>
   *    <li>
   *      every former member of <code>iface that is implementation only
   *    </li>
   *  </ul>
   */
  private class LazyImplClassType(iface: Symbol) extends LazyType {

    /** Compute the decls of implementation class <code>implClass, 
     *  given the decls <code>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 <code>tp refers to a non-interface trait, return a
   *  reference to its implementation class. Otherwise return <code>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
   *  <blockquote>
super[mix].$init$()
* to <code>tree. tree which is assumed to be the body * of a constructor of class <code>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 } } */

Other Scala examples (source code examples)

Here is a short list of links related to this Scala AddInterfaces.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.