summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/Flatten.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/Flatten.scala')
-rw-r--r--src/compiler/scala/tools/nsc/transform/Flatten.scala112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala
new file mode 100644
index 0000000000..031f7a0fcd
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala
@@ -0,0 +1,112 @@
+/* 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._;
+ import posAssigner.atPos;
+
+ /** the following two members override abstract members in Transform */
+ val phaseName: String = "flatten";
+
+ private def liftClass(sym: Symbol): unit =
+ if (!(sym hasFlag LIFTED)) {
+ sym setFlag LIFTED;
+ atPhase(phase.next) {
+ if (settings.debug.value) log("re-enter " + sym + " in " + sym.owner);
+ assert(sym.owner.isPackageClass, sym);//debug
+ val scope = sym.owner.info.decls;
+ val old = scope lookup sym.name;
+ if (old != NoSymbol) scope unlink old;
+ scope enter sym;
+ }
+ }
+
+ 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) =>
+ var parents1 = parents;
+ val decls1 = new Scope();
+ if (clazz.isPackageClass) {
+ atPhase(phase.next)(decls.toList foreach (decls1 enter));
+ } else {
+ val oldowner = clazz.owner;
+ atPhase(phase.next)(oldowner.info);
+ parents1 = List.mapConserve(parents)(this);
+ for (val sym <- decls.toList) {
+ if (sym.isTerm && !sym.isStaticModule) {
+ decls1 enter sym;
+ if (sym.isModule) sym.moduleClass setFlag LIFTED;
+ } else if (sym.isClass) {
+ liftClass(sym);
+ if (sym.needsImplClass) liftClass(erasure.implClass(sym))
+ }
+ }
+ }
+ ClassInfoType(parents1, decls1, clazz)
+ case PolyType(tparams, restp) =>
+ val restp1 = apply(restp);
+ if (restp1 eq restp) tp else PolyType(tparams, restp1)
+ 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 Select(qual, name) if (sym.isStaticModule && !sym.owner.isPackageClass) =>
+ atPhase(phase.next) {
+ atPos(tree.pos) {
+ gen.mkRef(sym)
+ }
+ }
+ case _ =>
+ tree
+ }
+ tree1 setType flattened(tree1.tpe)
+ }
+
+ /** 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
+ }
+ }
+}