|
1 | 1 | package scala.tools.nsc
|
2 | 2 | package transform
|
3 | 3 |
|
4 |
| -import symtab._ |
5 |
| -import Flags._ |
6 | 4 | import scala.collection._
|
7 |
| -import scala.language.postfixOps |
8 |
| -import scala.reflect.internal.Symbols |
9 | 5 | import scala.collection.mutable.LinkedHashMap
|
| 6 | +import scala.language.postfixOps |
| 7 | +import scala.tools.nsc.symtab.Flags._ |
| 8 | +import scala.tools.nsc.symtab._ |
10 | 9 |
|
11 | 10 | /**
|
12 | 11 | * 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
|
286 | 285 | localTyper.typedPos(decapturedFunction.pos)(ClassDef(lambdaClass, body)).asInstanceOf[ClassDef]
|
287 | 286 | }
|
288 | 287 |
|
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 |
296 | 292 | }
|
297 | 293 |
|
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] |
299 | 306 |
|
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 { |
301 | 312 | val anonymousClassDef = makeAnonymousClass
|
302 | 313 | 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)) |
308 | 315 | val typedNewStat = localTyper.typedPos(originalFunction.pos)(newStat)
|
309 |
| - |
310 | 316 | DelambdafyAnonClass(anonymousClassDef, typedNewStat)
|
311 | 317 | }
|
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 | 318 | }
|
344 | 319 |
|
345 | 320 | /**
|
@@ -491,4 +466,36 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
|
491 | 466 | }
|
492 | 467 |
|
493 | 468 | 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 | + } |
494 | 501 | }
|
0 commit comments