@@ -1414,7 +1414,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
1414
1414
def genLoadTry (tree : Try ): BType
1415
1415
1416
1416
def genInvokeDynamicLambda (ctor : Symbol , lambdaTarget : Symbol , environmentSize : Int , functionalInterface : Symbol ): BType = {
1417
- import java .lang .invoke .LambdaMetafactory .FLAG_SERIALIZABLE
1417
+ import java .lang .invoke .LambdaMetafactory .{ FLAG_BRIDGES , FLAG_SERIALIZABLE }
1418
1418
1419
1419
report.debuglog(s " Using invokedynamic rather than `new ${ctor.owner}` " )
1420
1420
val generatedType = classBTypeFromSymbol(functionalInterface)
@@ -1445,9 +1445,9 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
1445
1445
val functionalInterfaceDesc : String = generatedType.descriptor
1446
1446
val desc = capturedParamsTypes.map(tpe => toTypeKind(tpe)).mkString((" (" ), " " , " )" ) + functionalInterfaceDesc
1447
1447
// TODO specialization
1448
- val constrainedType = new MethodBType (lambdaParamTypes.map(p => toTypeKind(p)), toTypeKind(lambdaTarget.info.resultType)).toASMType
1448
+ val instantiatedMethodType = new MethodBType (lambdaParamTypes.map(p => toTypeKind(p)), toTypeKind(lambdaTarget.info.resultType)).toASMType
1449
1449
1450
- val abstractMethod = atPhase(erasurePhase) {
1450
+ val samMethod = atPhase(erasurePhase) {
1451
1451
val samMethods = toDenot(functionalInterface).info.possibleSamMethods.toList
1452
1452
samMethods match {
1453
1453
case x :: Nil => x.symbol
@@ -1457,21 +1457,40 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
1457
1457
}
1458
1458
}
1459
1459
1460
- val methodName = abstractMethod.javaSimpleName
1461
- val applyN = {
1462
- val mt = asmMethodType(abstractMethod)
1463
- mt.toASMType
1460
+ val methodName = samMethod.javaSimpleName
1461
+ val samMethodType = asmMethodType(samMethod).toASMType
1462
+ // scala/bug#10334: make sure that a lambda object for `T => U` has a method `apply(T)U`, not only the `(Object)Object`
1463
+ // version. Using the lambda a structural type `{def apply(t: T): U}` causes a reflective lookup for this method.
1464
+ val needsGenericBridge = samMethodType != instantiatedMethodType
1465
+ val bridgeMethods = atPhase(erasurePhase){
1466
+ samMethod.allOverriddenSymbols.toList
1464
1467
}
1465
- val bsmArgs0 = Seq (applyN, targetHandle, constrainedType)
1466
- val bsmArgs =
1467
- if (isSerializable)
1468
- bsmArgs0 :+ Int .box(FLAG_SERIALIZABLE )
1468
+ val overriddenMethodTypes = bridgeMethods.map(b => asmMethodType(b).toASMType)
1469
+
1470
+ // any methods which `samMethod` overrides need bridges made for them
1471
+ // this is done automatically during erasure for classes we generate, but LMF needs to have them explicitly mentioned
1472
+ // so we have to compute them at this relatively late point.
1473
+ val bridgeTypes = (
1474
+ if (needsGenericBridge)
1475
+ instantiatedMethodType +: overriddenMethodTypes
1469
1476
else
1470
- bsmArgs0
1477
+ overriddenMethodTypes
1478
+ ).distinct.filterNot(_ == samMethodType)
1479
+
1480
+ val needsBridges = bridgeTypes.nonEmpty
1481
+
1482
+ def flagIf (b : Boolean , flag : Int ): Int = if (b) flag else 0
1483
+ val flags = flagIf(isSerializable, FLAG_SERIALIZABLE ) | flagIf(needsBridges, FLAG_BRIDGES )
1484
+
1485
+ val bsmArgs0 = Seq (samMethodType, targetHandle, instantiatedMethodType)
1486
+ val bsmArgs1 = if (flags != 0 ) Seq (Int .box(flags)) else Seq .empty
1487
+ val bsmArgs2 = if needsBridges then bridgeTypes.length +: bridgeTypes else Seq .empty
1488
+
1489
+ val bsmArgs = bsmArgs0 ++ bsmArgs1 ++ bsmArgs2
1471
1490
1472
1491
val metafactory =
1473
- if (isSerializable )
1474
- lambdaMetaFactoryAltMetafactoryHandle // altMetafactory needed to be able to pass the SERIALIZABLE flag
1492
+ if (flags != 0 )
1493
+ lambdaMetaFactoryAltMetafactoryHandle // altMetafactory required to be able to pass the flags and additional arguments if needed
1475
1494
else
1476
1495
lambdaMetaFactoryMetafactoryHandle
1477
1496
0 commit comments