Skip to content

Commit 8a545ef

Browse files
committed
Small refactorings and additional comments in Delambdafy
1 parent 8a9efcc commit 8a545ef

File tree

1 file changed

+57
-50
lines changed

1 file changed

+57
-50
lines changed

src/compiler/scala/tools/nsc/transform/Delambdafy.scala

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package scala.tools.nsc
22
package transform
33

4-
import symtab._
5-
import Flags._
64
import scala.collection._
7-
import scala.language.postfixOps
8-
import scala.reflect.internal.Symbols
95
import scala.collection.mutable.LinkedHashMap
6+
import scala.language.postfixOps
7+
import scala.tools.nsc.symtab.Flags._
8+
import scala.tools.nsc.symtab._
109

1110
/**
1211
* This transformer is responsible for preparing lambdas for runtime, by either translating to anonymous classes
@@ -286,60 +285,36 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
286285
localTyper.typedPos(decapturedFunction.pos)(ClassDef(lambdaClass, body)).asInstanceOf[ClassDef]
287286
}
288287

289-
val useLambdaMetafactory = {
290-
val hasValueClass = exitingErasure {
291-
val methodType: Type = targetMethod(originalFunction).info
292-
methodType.exists(_.isInstanceOf[ErasedValueType])
293-
}
294-
val isTarget18 = settings.target.value.contains("jvm-1.8")
295-
settings.isBCodeActive && isTarget18 && !hasValueClass
288+
val allCaptureArgs: List[Tree] = {
289+
val thisArg = if (isStatic) Nil else (gen.mkAttributedThis(oldClass) setPos originalFunction.pos) :: Nil
290+
val captureArgs = captures.iterator.map(capture => gen.mkAttributedRef(capture) setPos originalFunction.pos).toList
291+
thisArg ::: captureArgs
296292
}
297293

298-
val thisArg = if (isStatic) Nil else (gen.mkAttributedThis(oldClass) setPos originalFunction.pos) :: Nil
294+
val functionalInterface = java8CompatFunctionalInterface(target, originalFunction.tpe)
295+
if (functionalInterface.exists) {
296+
// Create a symbol representing a fictional lambda factory method that accepts the captured
297+
// arguments and returns a Function.
298+
val msym = currentOwner.newMethod(nme.ANON_FUN_NAME, originalFunction.pos, ARTIFACT)
299+
val argTypes: List[Type] = allCaptureArgs.map(_.tpe)
300+
val params = msym.newSyntheticValueParams(argTypes)
301+
msym.setInfo(MethodType(params, originalFunction.tpe))
302+
val arity = originalFunction.vparams.length
303+
304+
// We then apply this symbol to the captures.
305+
val apply = localTyper.typedPos(originalFunction.pos)(Apply(Ident(msym), allCaptureArgs)).asInstanceOf[Apply]
299306

300-
def anonClass: TransformedFunction = {
307+
// The backend needs to know the target of the lambda and the functional interface in order
308+
// to emit the invokedynamic instruction. We pass this information as tree attachment.
309+
apply.updateAttachment(LambdaMetaFactoryCapable(target, arity, functionalInterface))
310+
InvokeDynamicLambda(apply)
311+
} else {
301312
val anonymousClassDef = makeAnonymousClass
302313
pkg.info.decls enter anonymousClassDef.symbol
303-
val captureArgs = captures map (capture => Ident(capture) setPos originalFunction.pos)
304-
305-
val newStat =
306-
Typed(New(anonymousClassDef.symbol, thisArg ++ captureArgs: _*), TypeTree(abstractFunctionErasedType))
307-
314+
val newStat = Typed(New(anonymousClassDef.symbol, allCaptureArgs: _*), TypeTree(abstractFunctionErasedType))
308315
val typedNewStat = localTyper.typedPos(originalFunction.pos)(newStat)
309-
310316
DelambdafyAnonClass(anonymousClassDef, typedNewStat)
311317
}
312-
313-
if (useLambdaMetafactory) {
314-
val arity = originalFunction.vparams.length
315-
val functionalInterface: Symbol = {
316-
val sym = originalFunction.tpe.typeSymbol
317-
val pack = currentRun.runDefinitions.Scala_Java8_CompatPackage
318-
val name1 = specializeTypes.specializedFunctionName(sym, originalFunction.tpe.typeArgs)
319-
if (name1.toTypeName == sym.name) {
320-
val returnUnit = restpe.typeSymbol == UnitClass
321-
val functionInterfaceArray =
322-
if (returnUnit) currentRun.runDefinitions.Scala_Java8_CompatPackage_JProcedure
323-
else currentRun.runDefinitions.Scala_Java8_CompatPackage_JFunction
324-
functionInterfaceArray.apply(arity)
325-
} else {
326-
pack.info.decl(name1.toTypeName.prepend("J"))
327-
}
328-
}
329-
if (functionalInterface.exists) {
330-
val captureArgs = captures.iterator.map(capture => gen.mkAttributedRef(capture) setPos originalFunction.pos).toList
331-
val allCaptureArgs = thisArg ++: captureArgs
332-
333-
val msym = currentOwner.newMethod(nme.ANON_FUN_NAME, originalFunction.pos, ARTIFACT)
334-
val argTypes: List[Type] = allCaptureArgs.map(_.tpe)
335-
val params = msym.newSyntheticValueParams(argTypes)
336-
msym.setInfo(MethodType(params, originalFunction.tpe))
337-
338-
val tree = localTyper.typedPos(originalFunction.pos)(Apply(Ident(msym), allCaptureArgs)).asInstanceOf[Apply]
339-
tree.updateAttachment(LambdaMetaFactoryCapable(targetMethod(originalFunction), arity, functionalInterface))
340-
InvokeDynamicLambda(tree)
341-
} else anonClass
342-
} else anonClass
343318
}
344319

345320
/**
@@ -491,4 +466,36 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
491466
}
492467

493468
final case class LambdaMetaFactoryCapable(target: Symbol, arity: Int, functionalInterface: Symbol)
469+
470+
// The functional interface that can be used to adapt the lambda target method `target` to the
471+
// given function type. Returns `NoSymbol` if the compiler settings are unsuitable, or `LambdaMetaFactory`
472+
// would be unable to generate the correct implementation (e.g. functions referring to derived value classes)
473+
private def java8CompatFunctionalInterface(target: Symbol, functionType: Type): Symbol = {
474+
val canUseLambdaMetafactory: Boolean = {
475+
val hasValueClass = exitingErasure {
476+
val methodType: Type = target.info
477+
methodType.exists(_.isInstanceOf[ErasedValueType])
478+
}
479+
val isTarget18 = settings.target.value.contains("jvm-1.8")
480+
settings.isBCodeActive && isTarget18 && !hasValueClass
481+
}
482+
483+
def functionalInterface: Symbol = {
484+
val sym = functionType.typeSymbol
485+
val pack = currentRun.runDefinitions.Scala_Java8_CompatPackage
486+
val name1 = specializeTypes.specializedFunctionName(sym, functionType.typeArgs)
487+
val paramTps :+ restpe = functionType.typeArgs
488+
val arity = paramTps.length
489+
if (name1.toTypeName == sym.name) {
490+
val returnUnit = restpe.typeSymbol == UnitClass
491+
val functionInterfaceArray =
492+
if (returnUnit) currentRun.runDefinitions.Scala_Java8_CompatPackage_JProcedure
493+
else currentRun.runDefinitions.Scala_Java8_CompatPackage_JFunction
494+
functionInterfaceArray.apply(arity)
495+
} else {
496+
pack.info.decl(name1.toTypeName.prepend("J"))
497+
}
498+
}
499+
if (canUseLambdaMetafactory) functionalInterface else NoSymbol
500+
}
494501
}

0 commit comments

Comments
 (0)