From eb8556ca663de9bf77514eab6e63f0a2f7599413 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 13 Feb 2012 21:55:15 -0800 Subject: Fix for SI-5444. Fix for trait/impl renaming in 5cbd7d06eb was incomplete. Looks more complete now. --- src/compiler/scala/reflect/internal/Symbols.scala | 9 ++++--- .../scala/tools/nsc/transform/AddInterfaces.scala | 5 ++-- .../scala/tools/nsc/transform/LambdaLift.scala | 31 ++++++++++++++++------ .../scala/tools/nsc/typechecker/Namers.scala | 2 +- 4 files changed, 32 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 69d881e8e1..77ed2f6a1b 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -1704,6 +1704,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => * (which is always the interface, by convention) * - before erasure, it looks up the interface name in the scope of the owner of the class. * This only works for implementation classes owned by other classes or traits. + * !!! Why? */ final def toInterface: Symbol = if (isImplClass) { @@ -2080,6 +2081,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => def infosString = infos.toString() + def debugLocationString = fullLocationString + " " + debugFlagString + def debugFlagString = hasFlagsToString(-1L) def hasFlagsToString(mask: Long): String = flagsToString( flags & mask, if (hasAccessBoundary) privateWithin.toString else "" @@ -2178,7 +2181,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => } def setLazyAccessor(sym: Symbol): TermSymbol = { - assert(isLazy && (referenced == NoSymbol || referenced == sym), (this, hasFlagsToString(-1L), referenced, sym)) + assert(isLazy && (referenced == NoSymbol || referenced == sym), (this, debugFlagString, referenced, sym)) referenced = sym this } @@ -2319,7 +2322,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Overridden in subclasses for which it makes sense. */ - def existentialBound: Type = abort("unexpected type: "+this.getClass+ " "+this.fullLocationString+ " " + hasFlagsToString(-1L)) + def existentialBound: Type = abort("unexpected type: "+this.getClass+ " "+debugLocationString) override def name: TypeName = super.name.asInstanceOf[TypeName] final override def isType = true @@ -2327,7 +2330,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def isAbstractType = { if (settings.debug.value) { if (isDeferred) { - println("TypeSymbol claims to be abstract type: " + this.getClass + " " + hasFlagsToString(-1L) + " at ") + println("TypeSymbol claims to be abstract type: " + this.getClass + " " + debugFlagString + " at ") (new Throwable).printStackTrace } } diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index e01bbccf13..b4ec8a23ce 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -94,7 +94,6 @@ abstract class AddInterfaces extends InfoTransform { // error: java.lang.AssertionError: assertion failed: (scala.tools.nsc.typechecker.Contexts$NoContext$,scala.tools.nsc.typechecker.Contexts,NoContext$,trait Contexts in package typechecker) / while parsing (/scala/trunk/build/pack/lib/scala-compiler.jar(scala/tools/nsc/interactive/ContextTrees$class.class),Some(class ContextTrees$class))trait Contexts.NoContext$ linkedModule: List() val originalImpl = impl - val originalImplString = originalImpl.hasFlagsToString(-1L) if (impl != NoSymbol) { // Unlink a pre-existing symbol only if the implementation class is // visible on the compilation classpath. In general this is true under @@ -120,8 +119,8 @@ abstract class AddInterfaces extends InfoTransform { impl setInfo new LazyImplClassType(iface) implClassMap(iface) = impl debuglog( - "generating impl class " + impl + " " + impl.hasFlagsToString(-1L) + " in " + iface.owner + ( - if (originalImpl == NoSymbol) "" else " (cloned from " + originalImpl.fullLocationString + " " + originalImplString + ")" + "generating impl class " + impl.debugLocationString + " in " + iface.owner + ( + if (originalImpl == NoSymbol) "" else " (cloned from " + originalImpl.debugLocationString + ")" ) ) impl diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 712298bd89..4fc7b9f92f 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -65,7 +65,10 @@ 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 + // (trait, name) -> owner + private val localTraits = mutable.HashMap[(Symbol, Name), Symbol]() + // (owner, name) -> implClass + private val localImplClasses = mutable.HashMap[(Symbol, Name), Symbol]() /** A flag to indicate whether new free variables have been found */ private var changedFreeVars: Boolean = _ @@ -167,8 +170,13 @@ abstract class LambdaLift extends InfoTransform { // 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 + if (sym.isImplClass) + localImplClasses((sym.owner, nme.interfaceName(sym.name))) = sym + else { + renamable addEntry sym + if (sym.isTrait) + localTraits((sym, sym.name)) = sym.owner + } } case DefDef(_, _, _, _, _, _) => if (sym.isLocal) { @@ -237,14 +245,21 @@ abstract class LambdaLift extends InfoTransform { 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) + // become Foo$class$1 instead.) Since the symbols are being renamed out from + // under us, and there's no reliable link between trait symbol and impl symbol, + // we have maps from ((trait, name)) -> owner and ((owner, name)) -> impl. + localTraits remove ((sym, sym.name)) match { + case None => renameSym(sym) + case Some(owner) => + localImplClasses remove ((owner, sym.name)) match { + case Some(implSym) => renameTrait(sym, implSym) + case _ => renameSym(sym) // pure interface, no impl class + } + } } atPhase(phase.next) { diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 0ff2b418f4..51542ec757 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -282,7 +282,7 @@ trait Namers extends MethodSynthesis { } private def logAssignSymbol(tree: Tree, sym: Symbol): Symbol = { - log("[+symbol] " + sym.hasFlagsToString(-1L) + " " + sym) + log("[+symbol] " + sym.debugLocationString) tree.symbol = sym sym } -- cgit v1.2.3