diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2013-11-27 15:13:50 +0100 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2013-12-19 15:27:06 +0100 |
commit | cca4d51dbf3f8478cb338e6d53e34003e9a3fa45 (patch) | |
tree | 047ae290cd9490c8494085f94dd07986ee801ec8 /src | |
parent | d99a4919e0fa4894829c752a8f881d7b103d8cda (diff) | |
download | scala-cca4d51dbf3f8478cb338e6d53e34003e9a3fa45.tar.gz scala-cca4d51dbf3f8478cb338e6d53e34003e9a3fa45.tar.bz2 scala-cca4d51dbf3f8478cb338e6d53e34003e9a3fa45.zip |
SI-5508 Fix crasher with private[this] in nested traits
Currently, accessors for private local trait fields are added
very late in the game when the `Mixin` tree transformer treats the
trait. By contrast, fields with weaker access have accessors created
eagerly in `Namers`.
// Mixin#addLateInterfaceMembers
val getter = member.getter(clazz)
if (getter == NoSymbol) addMember(clazz, newGetter(member))
`addMember` mutates the type of the interface to add the getter.
(This seems like a pretty poor design: usually if a phase changes
types, it should do in an `InfoTransformer`.)
However, if an inner class or anonymous function of the trait
has been flattened to a spot where it precedes the trait in the
enclosing packages info, this code hasn't had a chance to run,
and the lookup of the getter crashes as mixins `postTransform`
runs over a selection of the not-yet-materialized getter.
// Mixin#postTransform
case Select(qual, name) if sym.owner.isImplClass && !isStaticOnly(sym) =>
val iface = toInterface(sym.owner.tpe).typeSymbol
val ifaceGetter = sym getter iface
This commit ensures that `Flatten` lifts inner classes to
a position *after* the enclosing class in the stats of the
enclosing package.
Bonus fix: SI-7012 (the followup ticket to SI-6231 / SI-2897)
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Flatten.scala | 28 |
1 files changed, 22 insertions, 6 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala index e31211d321..b4329965fc 100644 --- a/src/compiler/scala/tools/nsc/transform/Flatten.scala +++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala @@ -100,23 +100,36 @@ abstract class Flatten extends InfoTransform { /** Buffers for lifted out classes */ private val liftedDefs = perRunCaches.newMap[Symbol, ListBuffer[Tree]]() - override def transform(tree: Tree): Tree = { + override def transform(tree: Tree): Tree = postTransform { tree match { case PackageDef(_, _) => liftedDefs(tree.symbol.moduleClass) = new ListBuffer + super.transform(tree) case Template(_, _, _) if tree.symbol.isDefinedInPackage => liftedDefs(tree.symbol.owner) = new ListBuffer + super.transform(tree) + case ClassDef(_, _, _, _) if tree.symbol.isNestedClass => + // SI-5508 Ordering important. In `object O { trait A { trait B } }`, we want `B` to appear after `A` in + // the sequence of lifted trees in the enclosing package. Why does this matter? Currently, mixin + // needs to transform `A` first to a chance to create accessors for private[this] trait fields + // *before* it transforms inner classes that refer to them. This also fixes SI-6231. + // + // Alternative solutions + // - create the private[this] accessors eagerly in Namer (but would this cover private[this] fields + // added later phases in compilation?) + // - move the accessor creation to the Mixin info transformer + val liftedBuffer = liftedDefs(tree.symbol.enclosingTopLevelClass.owner) + val index = liftedBuffer.length + liftedBuffer.insert(index, super.transform(tree)) + EmptyTree case _ => + super.transform(tree) } - 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.enclosingTopLevelClass.owner) += tree - EmptyTree case Select(qual, name) if sym.isStaticModule && !sym.isTopLevel => exitingFlatten { atPos(tree.pos) { @@ -134,7 +147,10 @@ abstract class Flatten extends InfoTransform { /** 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) stats1 ::: liftedDefs(currentOwner).toList + if (currentOwner.isPackageClass) { + val lifted = liftedDefs(currentOwner).toList + stats1 ::: lifted + } else stats1 } } |