diff options
author | Adriaan Moors <adriaan.moors@typesafe.com> | 2016-03-23 10:52:57 -0700 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@typesafe.com> | 2016-03-26 22:55:10 -0700 |
commit | 608ac2c2b9e3f6f46489e20830d8949ee7d506cf (patch) | |
tree | 8d995139a8a66f56fed90bf65f7ece5bf26d55d7 /src/compiler/scala/tools/nsc/transform | |
parent | 878e20a5243383300d3b4990146d260409bf5dfd (diff) | |
download | scala-608ac2c2b9e3f6f46489e20830d8949ee7d506cf.tar.gz scala-608ac2c2b9e3f6f46489e20830d8949ee7d506cf.tar.bz2 scala-608ac2c2b9e3f6f46489e20830d8949ee7d506cf.zip |
Soften sam restrictions
Some of the earlier proposals were too strongly linked to the
requirements of the Java 8 platform, which was problematic for
scala.js & friends.
Instead of ruling out SAM types that we can't compile to use
LambdaMetaFactory, expand those during compilation to anonymous
subclasses, instead of invokedynamic + LMF.
Also, self types rear their ugly heads again. Align `hasSelfType`
with the implementation suggested in `thisSym`'s docs.
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Delambdafy.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 27 |
2 files changed, 26 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala index 32ab52203e..7ccaec2f50 100644 --- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala +++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala @@ -239,7 +239,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre exitingErasure(target.info.paramTypes).map(reboxValueClass) :+ reboxValueClass(exitingErasure(target.info.resultType))).toTypeName val isSpecialized = specializedName != funSym.name - val functionalInterface = + val functionalInterface = // TODO: this is no longer needed, right? we can just use the regular function classes if (isSpecialized) currentRun.runDefinitions.Scala_Java8_CompatPackage.info.decl(specializedName.prepend("J")) else currentRun.runDefinitions.Scala_Java8_CompatPackage_JFunction(originalFunction.vparams.length) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 7e9e0e2a92..afa0fc92ff 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -74,7 +74,30 @@ abstract class UnCurry extends InfoTransform private val newMembers = mutable.Map[Symbol, mutable.Buffer[Tree]]() // Expand `Function`s in constructors to class instance creation (SI-6666, SI-8363) - private def mustExpandFunction = forceExpandFunction || inConstructorFlag != 0 + // We use Java's LambdaMetaFactory (LMF), which requires an interface for the sam's owner + private def mustExpandFunction(fun: Function) = forceExpandFunction || { + // (TODO: Can't use isInterface, yet, as it hasn't been updated for the new trait encoding) + val canUseLambdaMetaFactory = inConstructorFlag == 0 && (fun.attachments.get[SAMFunction].map(_.samTp) match { + case Some(userDefinedSamTp) => + val tpSym = erasure.javaErasure(userDefinedSamTp).typeSymbol // we only care about what ends up in the bytecode + ( + // LMF only supports interfaces + (tpSym.isJavaInterface || tpSym.isTrait) + // Unless tpSym.isStatic, even if the constructor is zero-argument now, it may acquire arguments in explicit outer or lambdalift. + // This is an impl restriction to simplify the decision of whether to expand the SAM during uncurry + // (when we don't yet know whether it will receive an outer pointer in explicit outer or whether lambda lift will add proxies for captures). + // When we delay sam expansion until after explicit outer & lambda lift, we could decide there whether + // to expand sam at compile time or use LMF, and this implementation restriction could be lifted. + && tpSym.isStatic + // impl restriction -- we currently use the boxed apply, so not really useful to allow specialized sam types (https://github.com/scala/scala/pull/4971#issuecomment-198119167) + && !tpSym.isSpecialized + ) + + case _ => true // our built-in FunctionN's are suitable for LambdaMetaFactory by construction + }) + + !canUseLambdaMetaFactory + } /** Add a new synthetic member for `currentOwner` */ private def addNewMember(t: Tree): Unit = @@ -191,7 +214,7 @@ abstract class UnCurry extends InfoTransform def transformFunction(fun: Function): Tree = // Undo eta expansion for parameterless and nullary methods if (fun.vparams.isEmpty && isByNameRef(fun.body)) { noApply += fun.body ; fun.body } - else if (mustExpandFunction) gen.expandFunction(localTyper)(fun, inConstructorFlag) + else if (mustExpandFunction(fun)) gen.expandFunction(localTyper)(fun, inConstructorFlag) else { // method definition with the same arguments, return type, and body as the original lambda val liftedMethod = gen.mkLiftedFunctionBodyMethod(localTyper)(fun.symbol.owner, fun) |