summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/LambdaLift.scala')
-rw-r--r--src/compiler/scala/tools/nsc/transform/LambdaLift.scala73
1 files changed, 53 insertions, 20 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
index 2180fd4f3a..712298bd89 100644
--- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
+++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala
@@ -9,7 +9,8 @@ package transform
import symtab._
import Flags._
import util.TreeSet
-import scala.collection.mutable.{ LinkedHashMap, ListBuffer }
+import scala.collection.{ mutable, immutable }
+import scala.collection.mutable.LinkedHashMap
abstract class LambdaLift extends InfoTransform {
import global._
@@ -64,6 +65,8 @@ abstract class LambdaLift extends InfoTransform {
/** The set of symbols that need to be renamed. */
private val renamable = newSymSet
+ private val renamableImplClasses = mutable.HashMap[Name, Symbol]() withDefaultValue NoSymbol
+
/** A flag to indicate whether new free variables have been found */
private var changedFreeVars: Boolean = _
@@ -152,7 +155,21 @@ abstract class LambdaLift extends InfoTransform {
tree match {
case ClassDef(_, _, _, _) =>
liftedDefs(tree.symbol) = Nil
- if (sym.isLocal) renamable addEntry sym
+ if (sym.isLocal) {
+ // Don't rename implementation classes independently of their interfaces. If
+ // the interface is to be renamed, then we will rename the implementation
+ // class at that time. You'd think we could call ".implClass" on the trait
+ // rather than collecting them in another map, but that seems to fail for
+ // exactly the traits being renamed here (i.e. defined in methods.)
+ //
+ // !!! - it makes no sense to have methods like "implClass" and
+ // "companionClass" which fail for an arbitrary subset of nesting
+ // arrangements, and then have separate methods which attempt to compensate
+ // for that failure. There should be exactly one method for any given
+ // entity which always gives the right answer.
+ if (sym.isImplClass) renamableImplClasses(nme.interfaceName(sym.name)) = sym
+ else renamable addEntry sym
+ }
case DefDef(_, _, _, _, _, _) =>
if (sym.isLocal) {
renamable addEntry sym
@@ -196,8 +213,8 @@ abstract class LambdaLift extends InfoTransform {
for (caller <- called.keys ; callee <- called(caller) ; fvs <- free get callee ; fv <- fvs)
markFree(fv, caller)
} while (changedFreeVars)
-
- for (sym <- renamable) {
+
+ def renameSym(sym: Symbol) {
val originalName = sym.name
val base = sym.name + nme.NAME_JOIN_STRING + (
if (sym.isAnonymousFunction && sym.owner.isMethod)
@@ -211,19 +228,35 @@ abstract class LambdaLift extends InfoTransform {
debuglog("renaming in %s: %s => %s".format(sym.owner.fullLocationString, originalName, sym.name))
}
+ /** Rename a trait's interface and implementation class in coordinated fashion.
+ */
+ def renameTrait(traitSym: Symbol, implSym: Symbol) {
+ val originalImplName = implSym.name
+ renameSym(traitSym)
+ implSym.name = nme.implClassName(traitSym.name)
+
+ debuglog("renaming impl class in step with %s: %s => %s".format(traitSym, originalImplName, implSym.name))
+ }
+
+ for (sym <- renamable) {
+ // If we renamed a trait from Foo to Foo$1, we must rename the implementation
+ // class from Foo$class to Foo$1$class. (Without special consideration it would
+ // become Foo$class$1 instead.)
+ val implClass = if (sym.isTrait) renamableImplClasses(sym.name) else NoSymbol
+ if ((implClass ne NoSymbol) && (sym.owner == implClass.owner)) renameTrait(sym, implClass)
+ else renameSym(sym)
+ }
+
atPhase(phase.next) {
for ((owner, freeValues) <- free.toList) {
+ val newFlags = SYNTHETIC | ( if (owner.isClass) PARAMACCESSOR | PrivateLocal else PARAM )
debuglog("free var proxy: %s, %s".format(owner.fullLocationString, freeValues.toList.mkString(", ")))
-
- proxies(owner) =
- for (fv <- freeValues.toList) yield {
- val proxy = owner.newValue(owner.pos, fv.name)
- .setFlag(if (owner.isClass) PARAMACCESSOR | PrivateLocal else PARAM)
- .setFlag(SYNTHETIC)
- .setInfo(fv.info);
- if (owner.isClass) owner.info.decls enter proxy;
- proxy
- }
+ proxies(owner) =
+ for (fv <- freeValues.toList) yield {
+ val proxy = owner.newValue(fv.name, owner.pos, newFlags) setInfo fv.info
+ if (owner.isClass) owner.info.decls enter proxy
+ proxy
+ }
}
}
}
@@ -409,12 +442,12 @@ abstract class LambdaLift extends InfoTransform {
}
else tree1
case Block(stats, expr0) =>
- val (lzyVals, rest) = stats.partition {
- case stat@ValDef(_, _, _, _) if stat.symbol.isLazy => true
- case stat@ValDef(_, _, _, _) if stat.symbol.hasFlag(MODULEVAR) => true
- case _ => false
- }
- treeCopy.Block(tree, lzyVals:::rest, expr0)
+ val (lzyVals, rest) = stats partition {
+ case stat: ValDef => stat.symbol.isLazy || stat.symbol.isModuleVar
+ case _ => false
+ }
+ if (lzyVals.isEmpty) tree
+ else treeCopy.Block(tree, lzyVals ::: rest, expr0)
case _ =>
tree
}