diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/LambdaLift.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/LambdaLift.scala | 73 |
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 } |