summaryrefslogtreecommitdiff
path: root/src/compiler/scala
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2016-06-06 13:34:18 +1000
committerJason Zaugg <jzaugg@gmail.com>2016-06-06 13:34:18 +1000
commit3bb735823f6815002895b1a335c6d105ddbe3e9e (patch)
tree5136e824612af0aa0a11675845713fd8a5101a70 /src/compiler/scala
parent361f3f1540c755e36aaed22484924bb44eabc83b (diff)
parentf07019ffa56ec2dfab8ab0d9a83133005761a877 (diff)
downloadscala-3bb735823f6815002895b1a335c6d105ddbe3e9e.tar.gz
scala-3bb735823f6815002895b1a335c6d105ddbe3e9e.tar.bz2
scala-3bb735823f6815002895b1a335c6d105ddbe3e9e.zip
Merge pull request #5099 from retronym/ticket/9390
SI-9390 Emit local defs that don't capture this as static
Diffstat (limited to 'src/compiler/scala')
-rw-r--r--src/compiler/scala/tools/nsc/transform/Constructors.scala3
-rw-r--r--src/compiler/scala/tools/nsc/transform/Delambdafy.scala43
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala4
3 files changed, 39 insertions, 11 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala
index 636fb08b89..971a55f763 100644
--- a/src/compiler/scala/tools/nsc/transform/Constructors.scala
+++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala
@@ -715,6 +715,9 @@ abstract class Constructors extends Statics with Transform with ast.TreeDSL {
primaryConstrBody.expr)
})
+ if (omittableAccessor.exists(_.isOuterField) && !constructorStats.exists(_.exists { case i: Ident if i.symbol.isOuterParam => true; case _ => false}))
+ primaryConstructor.symbol.updateAttachment(OuterArgCanBeElided)
+
val constructors = primaryConstructor :: auxConstructors
// Unlink all fields that can be dropped from class scope
diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala
index 1dfc1330c6..2dd8def53e 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,10 +273,21 @@ 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 Apply(fun, outer :: rest) if shouldElideOuterArg(fun.symbol, outer) =>
+ val nullOuter = gen.mkZero(outer.tpe)
+ treeCopy.Apply(tree, transform(fun), nullOuter :: transformTrees(rest))
case _ => super.transform(tree)
}
} // DelambdafyTransformer
+ private def shouldElideOuterArg(fun: Symbol, outerArg: Tree): Boolean =
+ fun.isConstructor && treeInfo.isQualifierSafeToElide(outerArg) && fun.hasAttachment[OuterArgCanBeElided.type]
// A traverser that finds symbols used but not defined in the given Tree
// TODO freeVarTraverser in LambdaLift does a very similar task. With some
@@ -326,19 +338,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 +370,12 @@ 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 Apply(fun, outer :: rest) if shouldElideOuterArg(fun.symbol, outer) =>
+ super.traverse(fun)
+ super.traverseTrees(rest)
case This(_) =>
if (currentMethod.exists && tree.symbol == currentMethod.enclClass) {
debuglog(s"$currentMethod directly refers to 'this'")
diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
index 3d6fad4238..411ff6b9be 100644
--- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
+++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala
@@ -67,8 +67,6 @@ abstract class ExplicitOuter extends InfoTransform
result
}
- private val innerClassConstructorParamName: TermName = newTermName("arg" + nme.OUTER)
-
class RemoveBindingsTransformer(toRemove: Set[Symbol]) extends Transformer {
override def transform(tree: Tree) = tree match {
case Bind(_, body) if toRemove(tree.symbol) => super.transform(body)
@@ -169,7 +167,7 @@ abstract class ExplicitOuter extends InfoTransform
val paramsWithOuter =
if (sym.isClassConstructor && isInner(sym.owner)) // 1
- sym.newValueParameter(innerClassConstructorParamName, sym.pos).setInfo(sym.owner.outerClass.thisType) :: params
+ sym.newValueParameter(nme.OUTER_ARG, sym.pos).setInfo(sym.owner.outerClass.thisType) :: params
else params
if ((resTpTransformed ne resTp) || (paramsWithOuter ne params)) MethodType(paramsWithOuter, resTpTransformed)