Skip to content

Commit 3bf208f

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

File tree

1 file changed

+54
-46
lines changed

1 file changed

+54
-46
lines changed

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

Lines changed: 54 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -286,60 +286,36 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
286286
localTyper.typedPos(decapturedFunction.pos)(ClassDef(lambdaClass, body)).asInstanceOf[ClassDef]
287287
}
288288

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
289+
val allCaptureArgs: List[Tree] = {
290+
val thisArg = if (isStatic) Nil else (gen.mkAttributedThis(oldClass) setPos originalFunction.pos) :: Nil
291+
val captureArgs = captures.iterator.map(capture => gen.mkAttributedRef(capture) setPos originalFunction.pos).toList
292+
thisArg ::: captureArgs
296293
}
297294

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

300-
def anonClass: TransformedFunction = {
308+
// The backend needs to know the target of the lambda and the functional interface in order
309+
// to emit the invokedynamic instruction. We pass this information as tree attachment.
310+
apply.updateAttachment(LambdaMetaFactoryCapable(target, arity, functionalInterface))
311+
InvokeDynamicLambda(apply)
312+
} else {
301313
val anonymousClassDef = makeAnonymousClass
302314
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-
315+
val newStat = Typed(New(anonymousClassDef.symbol, allCaptureArgs: _*), TypeTree(abstractFunctionErasedType))
308316
val typedNewStat = localTyper.typedPos(originalFunction.pos)(newStat)
309-
310317
DelambdafyAnonClass(anonymousClassDef, typedNewStat)
311318
}
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
343319
}
344320

345321
/**
@@ -491,4 +467,36 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
491467
}
492468

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

0 commit comments

Comments
 (0)