@@ -286,60 +286,36 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
286
286
localTyper.typedPos(decapturedFunction.pos)(ClassDef (lambdaClass, body)).asInstanceOf [ClassDef ]
287
287
}
288
288
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
296
293
}
297
294
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 ]
299
307
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 {
301
313
val anonymousClassDef = makeAnonymousClass
302
314
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))
308
316
val typedNewStat = localTyper.typedPos(originalFunction.pos)(newStat)
309
-
310
317
DelambdafyAnonClass (anonymousClassDef, typedNewStat)
311
318
}
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
343
319
}
344
320
345
321
/**
@@ -491,4 +467,36 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
491
467
}
492
468
493
469
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
+ }
494
502
}
0 commit comments