summaryrefslogblamecommitdiff
path: root/sources/scala/tools/nsc/transform/Flatten.scala
blob: 020f4c54addf4e75896c087a3cc4acf94369f0c6 (plain) (tree)
























                                                                                           










                                                         






                                                                 
                                                                                   
 
                                       































                                                                                               
                                                                                


















                                                                                     
/* 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 Flatten extends InfoTransform {
  import global._;
  import definitions._;

  /** the following two members override abstract members in Transform */
  val phaseName: String = "flatten";

  private val flattened = new TypeMap {
    def apply(tp: Type): Type = tp match {
      case TypeRef(pre, sym, args) if (pre.symbol.isClass && !pre.symbol.isPackageClass) =>
        assert(args.isEmpty);
        typeRef(sym.toplevelClass.owner.thisType, sym, args)
      case ClassInfoType(parents, decls, clazz) =>
        if (clazz.isPackageClass) {
          val decls1 = new Scope();
          for (val member <- decls.toList) {
            atPhase(phase.next)(decls1 enter member)
          }
          ClassInfoType(parents, decls1, clazz)
        } else {
	  val parents1 = List.mapConserve(parents)(this);
	  if (parents1 eq parents) tp
	  else ClassInfoType(parents1, decls, clazz)
        }
      case _ =>
        mapOver(tp)
    }
  }

  def transformInfo(sym: Symbol, tp: Type): Type = flattened(tp);

  protected def newTransformer(unit: CompilationUnit): Transformer = new Flattener;

  class Flattener extends Transformer {

    /** Buffers for lifted out classes */
    private val liftedDefs = new HashMap[Symbol, ListBuffer[Tree]];

    override def transform(tree: Tree): Tree = {
      tree match {
      	case PackageDef(_, _) =>
          liftedDefs(tree.symbol.moduleClass) = new ListBuffer;
	case _ =>
      }
      postTransform(super.transform(tree))
    }

    private def postTransform(tree: Tree): Tree = {
      val sym = tree.symbol;
      val tree1 = tree match {
        case ClassDef(_, _, _, _, _) if sym.isNestedClass =>
	  liftedDefs(sym.toplevelClass.owner) += tree;
	  EmptyTree
	case Super(qual, mix) if (mix != nme.EMPTY.toTypeName) =>
	  val ps = tree.symbol.info.parents dropWhile (p => p.symbol.name != mix);
	  assert(!ps.isEmpty, tree);
	  val mix1 = if (ps.head.symbol.isNestedClass) atPhase(phase.next)(ps.head.symbol.name)
		     else mix;
	  copy.Super(tree, qual, mix1)
        case _ =>
          tree
      }
      tree1 setType flattened(tree1.tpe);
      if (sym != null && sym.isNestedClass && !(sym hasFlag FLATTENED)) {
	sym setFlag FLATTENED;
	atPhase(phase.next) {
	  if (settings.debug.value) log("re-enter " + sym + " in " + sym.owner);
	  val scope = sym.owner.info.decls;
	  val old = scope lookup sym.name;
	  if (old != NoSymbol) scope unlink old;
	  scope enter sym;
	}
      }
      tree1
    }

    /** Transform statements and add lifted definitions to them. */
    override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = {
      val stats1 = super.transformStats(stats, exprOwner);
      if (currentOwner.isPackageClass && liftedDefs(currentOwner).hasNext)
        stats1 ::: liftedDefs(currentOwner).toList
      else
        stats1
    }
  }
}