@@ -1414,7 +1414,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
14141414 def genLoadTry (tree : Try ): BType
14151415
14161416 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 }
14181418
14191419 report.debuglog(s " Using invokedynamic rather than `new ${ctor.owner}` " )
14201420 val generatedType = classBTypeFromSymbol(functionalInterface)
@@ -1445,9 +1445,9 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
14451445 val functionalInterfaceDesc : String = generatedType.descriptor
14461446 val desc = capturedParamsTypes.map(tpe => toTypeKind(tpe)).mkString((" (" ), " " , " )" ) + functionalInterfaceDesc
14471447 // 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
14491449
1450- val abstractMethod = atPhase(erasurePhase) {
1450+ val samMethod = atPhase(erasurePhase) {
14511451 val samMethods = toDenot(functionalInterface).info.possibleSamMethods.toList
14521452 samMethods match {
14531453 case x :: Nil => x.symbol
@@ -1457,21 +1457,40 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
14571457 }
14581458 }
14591459
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
14641467 }
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
14691476 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
14711490
14721491 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
14751494 else
14761495 lambdaMetaFactoryMetafactoryHandle
14771496
0 commit comments