summaryrefslogblamecommitdiff
path: root/sources/scala/tools/nsc/transform/AddInterfaces.scala
blob: 5f8fd1b91cae5b9b9e4d33e224e552d18e84b7e7 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
















                                                                    
                                                                  







                                                          
                                                                  
                       

                        

   

                                                     
                                                                              
 

                                                         
                 

                                                                
   
 
                                                                        

                     
                                        
                                                     
                                                                                          




                                                                    
                              
                                                                            
                                                  
                                   
                                                                                                     










                                                                   
                                                                                            

                                                            
                                    











                                                




                                                                                                    


                                             
                                                                          





                                                            
                                                           




                                        

                                                     




                                                  

                                   
                                                                                     
                                                                                 
                                                                    
                                           
         



                                                                                                





                                                                                     









                                                                                 













                                                                                     
                                                                        
                  
                                                                








                                                                                        
                      
                                               

                                                                    






                                                      
                                         










                                                                                   

                                                            


                                                        
                                           




                                                                                          

                                                                                               
                       
                                           





                                                                              



                                                
                                                         


                                                                              
                                                                               

                      
                                                                                             














                                                                                      
                                                       

















                                                      
/* NSC -- new scala compiler
 * Copyright 2005 LAMP/EPFL
 * @author
 */
// $Id$
package scala.tools.nsc.transform;

import symtab._;
import Flags._;
import util.ListBuffer;
import collection.mutable.HashMap;

abstract class AddInterfaces extends InfoTransform {
  import global._;                  // the global environment
  import definitions._;             // standard classes and methods
  import posAssigner.atPos;         // for filling in tree positions

  override def phaseNewFlags: long = lateDEFERRED | lateINTERFACE;

// Type transformation

  def erasedTypeRef(sym: Symbol): Type;

  private val implClassMap = new HashMap[Symbol, Symbol];
  private val implMethodMap = new HashMap[Symbol, Symbol];

  override def newPhase(prev: scala.tools.nsc.Phase): StdPhase = {
    implClassMap.clear;
    implMethodMap.clear;
    super.newPhase(prev)
  }

  private def needsImplMethod(sym: Symbol): boolean =
    sym.isMethod && isInterfaceMember(sym) &&
    (!(sym hasFlag (DEFERRED | SUPERACCESSOR)) || (sym hasFlag lateDEFERRED));

  private def isInterfaceMember(sym: Symbol): boolean = {
    sym.info; // to set lateMETHOD flag if necessary
    sym.isType ||
    sym.isMethod && !(sym hasFlag (PRIVATE | BRIDGE | LABEL)) &&
    !sym.isConstructor && !sym.isImplOnly
  }

  def implClass(iface: Symbol): Symbol = implClassMap.get(iface) match {
    case Some(c) => c
    case None =>
      atPhase(currentRun.erasurePhase) {
        val implName = nme.implClassName(iface.name);
        var impl = if (iface.owner.isClass) iface.owner.info.decl(implName) else NoSymbol;
        if (impl == NoSymbol) {
          impl = iface.cloneSymbolImpl(iface.owner);
          impl.name = implName;
          if (iface.owner.isClass) iface.owner.info.decls enter impl
        }
        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
      }
  }

  private class LazyImplClassType(iface: Symbol) extends LazyType {

    def implDecls(implClass: Symbol, ifaceDecls: Scope): Scope = {
      val decls = new Scope();
      for (val sym <- ifaceDecls.elements) {
        if (isInterfaceMember(sym)) {
          if (needsImplMethod(sym)) {
	    val impl = sym.cloneSymbol(implClass).setInfo(sym.info).resetFlag(lateDEFERRED);
	    if (!impl.isExternal) implMethodMap(sym) = impl;
	    decls enter impl;
	    sym setFlag lateDEFERRED
          }
        } else {
	  sym.owner = implClass;
          decls enter sym;
	}
      }
      decls
    }

    override def complete(sym: Symbol): unit = {
      def implType(tp: Type): Type = tp match {
	case ClassInfoType(parents, decls, _) =>
	  //ClassInfoType(traitToImplClass(parents) ::: List(iface.tpe), implDecls(sym, decls), sym)
	  ClassInfoType(
            ObjectClass.tpe :: (parents.tail map traitToImplClass) ::: List(iface.tpe),
            implDecls(sym, decls),
            sym)
	case PolyType(tparams, restpe) =>
	  PolyType(tparams, implType(restpe))
      }
      sym.setInfo(atPhase(currentRun.erasurePhase)(implType(iface.info)));
    }

    override def load(clazz: Symbol): unit = complete(clazz)
  }

  private def traitToImplClass(tp: Type): Type = tp match {
    case TypeRef(pre, sym, args) if (sym.needsImplClass) =>
      typeRef(pre, implClass(sym), args)
    case _ =>
      tp
  }

  def transformTraitInfo(tp: Type): Type = tp match {
    case ClassInfoType(parents, decls, clazz) =>
      if (clazz.needsImplClass) {
        clazz setFlag lateINTERFACE;
        implClass(clazz) // generate an impl class
      }
      val parents1 =
        if (parents.isEmpty) List()
        else {
          assert(!parents.head.symbol.isTrait || clazz == RepeatedParamClass, clazz);
          if (clazz hasFlag INTERFACE) erasedTypeRef(ObjectClass) :: parents.tail
          else if (clazz.isImplClass || clazz == ArrayClass) parents
	  else parents map traitToImplClass
        }
      val decls1 = if (clazz hasFlag INTERFACE) new Scope(decls.toList filter isInterfaceMember)
                   else decls;
      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): unit = {
      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, vparamss => EmptyTree)
    else tree;

  private def ifaceTemplate(templ: Template): Template =
    copy.Template(templ, templ.parents, 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 =>
        throw new Error("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 implTemplate(clazz: Symbol, templ: Template): Template = atPos(templ.pos){
    val templ1 = Template(templ.parents, templ.body map implMemberDef)
      setPos templ.pos
      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] = {
    val buf = new ListBuffer[Tree];
    for (val tree <- trees)
      tree match {
	case ClassDef(_, _, _, _, impl) =>
	  if (tree.symbol.needsImplClass)
            buf += {
              val clazz = implClass(tree.symbol).initialize;
              ClassDef(clazz, implTemplate(clazz, impl))
            }
	case _ =>
      }
    buf.toList
  }

  protected val traitTransformer = 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 tree1 = tree match {
	case ClassDef(mods, name, tparams, tpt, impl) =>
	  if (tree.symbol.needsImplClass) {
            implClass(tree.symbol).initialize; // to force lateDEFERRED flags
	    copy.ClassDef(tree, mods | INTERFACE, name, tparams, tpt, ifaceTemplate(impl))
          }
	  else tree
	case Template(parents, body) =>
          val parents1 = tree.symbol.owner.info.parents map (t => TypeTree(t) setPos tree.pos);
          copy.Template(tree, parents1, body)
	case This(_) =>
	  if (tree.symbol.needsImplClass) {
            val impl = implClass(tree.symbol);
            var owner = currentOwner;
            while (owner != tree.symbol && owner != impl) owner = owner.owner;
            if (owner == impl) This(impl) setPos tree.pos
            else tree
          } else tree
	case Super(qual, mix) =>
	  val mix1 =
	    if (mix == nme.EMPTY.toTypeName) mix
	    else {
	      val ps = atPhase(currentRun.erasurePhase) {
                tree.symbol.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 (tree.symbol.needsImplClass) Super(implClass(tree.symbol), mix1) setPos tree.pos
	  else copy.Super(tree, qual, mix1)
	case _ =>
	  tree
      }
      super.transform(tree1)
    }
  }
}
/*
    val ensureNoEscapes = new TypeTraverser {
      def ensureNoEscape(sym: Symbol): unit = {
        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
      }
    }

*/