diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2012-05-25 08:07:28 +0200 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2012-05-26 18:47:12 +0200 |
commit | 4794374af4d7c84ed6e06ac9c4e4f9f9d09cb102 (patch) | |
tree | d89f47528c5ed60970b4321aa0d6169a880a240a /src/compiler | |
parent | 123050cf07229d02789dc42e27a85c93fd9343a4 (diff) | |
download | scala-4794374af4d7c84ed6e06ac9c4e4f9f9d09cb102.tar.gz scala-4794374af4d7c84ed6e06ac9c4e4f9f9d09cb102.tar.bz2 scala-4794374af4d7c84ed6e06ac9c4e4f9f9d09cb102.zip |
SI-5652 Mangle names of potentially public lambda lifted methods.
This can happen if they are accessed from an inner class. If a
subclass is happens to lift a public method to the same name,
a VerifyError ensues.
The enclosed tests:
- demonstrate the absense of the VerifyError
- show the names generated for the lifted methods (which are
unchanged if not called from an inner class, or if lifted
into a trait implementation class.)
- ensure that the callers are rewritten to call the correct
method when multiple with the same name are lifted.
It's not ideal that this phase needs a priori knowledge of the
later phases to perform this mangling. A better fix would defer
this until the point when the methods are publicised, and leave
the unmangled private method in place and install an public,
mangled forwarder.
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/LambdaLift.scala | 33 |
1 files changed, 21 insertions, 12 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 718e58b855..fad41ae98d 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -10,7 +10,7 @@ import symtab._ import Flags._ import util.TreeSet import scala.collection.{ mutable, immutable } -import scala.collection.mutable.LinkedHashMap +import scala.collection.mutable.{ LinkedHashMap, LinkedHashSet } abstract class LambdaLift extends InfoTransform { import global._ @@ -50,6 +50,9 @@ abstract class LambdaLift extends InfoTransform { /** A hashtable storing calls between functions */ private val called = new LinkedHashMap[Symbol, SymSet] + /** Symbols that are called from an inner class. */ + private val calledFromInner = new LinkedHashSet[Symbol] + /** The set of symbols that need to be renamed. */ private val renamable = newSymSet @@ -64,9 +67,6 @@ abstract class LambdaLift extends InfoTransform { /** Buffers for lifted out classes and methods */ private val liftedDefs = new LinkedHashMap[Symbol, List[Tree]] - /** True if we are transforming under a ReferenceToBoxed node */ - private var isBoxedRef = false - private type SymSet = TreeSet[Symbol] private def newSymSet = new TreeSet[Symbol](_ isLess _) @@ -138,6 +138,7 @@ abstract class LambdaLift extends InfoTransform { private def markCalled(sym: Symbol, owner: Symbol) { debuglog("mark called: " + sym + " of " + sym.owner + " is called by " + owner) symSet(called, owner) addEntry sym + if (sym.enclClass != owner.enclClass) calledFromInner addEntry sym } /** The traverse function */ @@ -214,15 +215,23 @@ abstract class LambdaLift extends InfoTransform { def renameSym(sym: Symbol) { val originalName = sym.name - val base = sym.name + nme.NAME_JOIN_STRING + ( - if (sym.isAnonymousFunction && sym.owner.isMethod) - sym.owner.name + nme.NAME_JOIN_STRING - else "" - ) - sym setName ( - if (sym.name.isTypeName) unit.freshTypeName(base) - else unit.freshTermName(base) + def freshen(prefix: String): Name = + if (originalName.isTypeName) unit.freshTypeName(prefix) + else unit.freshTermName(prefix) + + val newName: Name = ( + if (sym.isAnonymousFunction && sym.owner.isMethod) { + freshen(sym.name + nme.NAME_JOIN_STRING + sym.owner.name + nme.NAME_JOIN_STRING) + } else { + // SI-5652 If the lifted symbol is accessed from an inner class, it will be made public. (where?) + // Generating a a unique name, mangled with the enclosing class name, avoids a VerifyError + // in the case that a sub-class happens to lifts out a method with the *same* name. + val name = freshen(sym.name + nme.NAME_JOIN_STRING) + if (originalName.isTermName && !sym.enclClass.isImplClass && calledFromInner(sym)) nme.expandedName(name, sym.enclClass) + else name + } ) + sym setName newName debuglog("renaming in %s: %s => %s".format(sym.owner.fullLocationString, originalName, sym.name)) } |