summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2016-04-14 14:00:33 +1000
committerJason Zaugg <jzaugg@gmail.com>2016-06-01 11:19:54 +1000
commite077c24525bf8f9bd8b73684e630eb7fc6bcb5f6 (patch)
treead9468ed7023c9cbf129585aea73730413d3e2af /src/compiler/scala/tools/nsc/transform/Delambdafy.scala
parentf01d061caaae26b3fdff0e4db800292e9b3252c2 (diff)
downloadscala-e077c24525bf8f9bd8b73684e630eb7fc6bcb5f6.tar.gz
scala-e077c24525bf8f9bd8b73684e630eb7fc6bcb5f6.tar.bz2
scala-e077c24525bf8f9bd8b73684e630eb7fc6bcb5f6.zip
SI-9390 Emit local defs that don't capture this as static
This avoids unnecessary memory retention, and allows lambdas that call the local methods to be serializable, regardless of whether or not the enclosing class is serializable. The second point is especially pressing, given that the enclosing class for local methods defined in a used to be the (serializable) anonymous function class, but as of Scala 2.12 will be the enclosing class of the lambda. This change is similar in spirit to SI-9408 / 93bee55e.
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/Delambdafy.scala')
-rw-r--r--src/compiler/scala/tools/nsc/transform/Delambdafy.scala35
1 files changed, 27 insertions, 8 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
index 1dfc1330c6..a8933a9ee6 100644
--- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
+++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
@@ -225,6 +225,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
}
}
+
private def transformFunction(originalFunction: Function): Tree = {
val target = targetMethod(originalFunction)
assert(target.hasFlag(Flags.STATIC))
@@ -272,6 +273,12 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
val Template(parents, self, body) = super.transform(deriveTemplate(tree)(_.mapConserve(pretransform)))
Template(parents, self, body ++ boxingBridgeMethods)
} finally boxingBridgeMethods.clear()
+ case dd: DefDef if dd.symbol.isLiftedMethod && !dd.symbol.isDelambdafyTarget =>
+ // SI-9390 emit lifted methods that don't require a `this` reference as STATIC
+ // delambdafy targets are excluded as they are made static by `transformFunction`.
+ if (!dd.symbol.hasFlag(STATIC) && !methodReferencesThis(dd.symbol))
+ dd.symbol.setFlag(STATIC)
+ super.transform(tree)
case _ => super.transform(tree)
}
} // DelambdafyTransformer
@@ -326,19 +333,28 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
// recursively find methods that refer to 'this' directly or indirectly via references to other methods
// for each method found add it to the referrers set
- private def refersToThis(symbol: Symbol): Boolean =
- (thisReferringMethods contains symbol) ||
- (liftedMethodReferences(symbol) exists refersToThis) && {
- // add it early to memoize
- debuglog(s"$symbol indirectly refers to 'this'")
- thisReferringMethods += symbol
- true
+ private def refersToThis(symbol: Symbol): Boolean = {
+ var seen = mutable.Set[Symbol]()
+ def loop(symbol: Symbol): Boolean = {
+ if (seen(symbol)) false
+ else {
+ seen += symbol
+ (thisReferringMethods contains symbol) ||
+ (liftedMethodReferences(symbol) exists loop) && {
+ // add it early to memoize
+ debuglog(s"$symbol indirectly refers to 'this'")
+ thisReferringMethods += symbol
+ true
+ }
}
+ }
+ loop(symbol)
+ }
private var currentMethod: Symbol = NoSymbol
override def traverse(tree: Tree) = tree match {
- case DefDef(_, _, _, _, _, _) if tree.symbol.isDelambdafyTarget =>
+ case DefDef(_, _, _, _, _, _) if tree.symbol.isDelambdafyTarget || tree.symbol.isLiftedMethod =>
// we don't expect defs within defs. At this phase trees should be very flat
if (currentMethod.exists) devWarning("Found a def within a def at a phase where defs are expected to be flattened out.")
currentMethod = tree.symbol
@@ -349,6 +365,9 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
// They'll be of the form {(args...) => this.anonfun(args...)}
// but we do need to make note of the lifted body method in case it refers to 'this'
if (currentMethod.exists) liftedMethodReferences(currentMethod) += targetMethod(fun)
+ case Apply(sel @ Select(This(_), _), args) if sel.symbol.isLiftedMethod =>
+ if (currentMethod.exists) liftedMethodReferences(currentMethod) += sel.symbol
+ super.traverseTrees(args)
case This(_) =>
if (currentMethod.exists && tree.symbol == currentMethod.enclClass) {
debuglog(s"$currentMethod directly refers to 'this'")