From 24d8ecbf6d498d58e35e53910bf2ec6de8d0e060 Mon Sep 17 00:00:00 2001 From: Daniel Thoma Date: Thu, 20 Feb 2025 22:30:18 +0100 Subject: [PATCH] Fixes #15736 Box native instantiated method return type if sam method return type is not a primitive type to satisfy conditions specified in https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/LambdaMetafactory.html Condition is not enforced by JVM but by Android ART. --- .../tools/backend/jvm/BCodeBodyBuilder.scala | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala index 35b24ab57b00..1eba6c0b1bf8 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala @@ -1773,8 +1773,6 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { val returnUnit = lambdaTarget.info.resultType.typeSymbol == defn.UnitClass val functionalInterfaceDesc: String = generatedType.descriptor val desc = capturedParamsTypes.map(tpe => toTypeKind(tpe)).mkString(("("), "", ")") + functionalInterfaceDesc - // TODO specialization - val instantiatedMethodType = new MethodBType(lambdaParamTypes.map(p => toTypeKind(p)), toTypeKind(lambdaTarget.info.resultType)).toASMType val samMethod = atPhase(erasurePhase) { val samMethods = toDenot(functionalInterface).info.possibleSamMethods.toList @@ -1787,7 +1785,21 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { } val methodName = samMethod.javaSimpleName - val samMethodType = asmMethodType(samMethod).toASMType + val samMethodBType = asmMethodType(samMethod) + val samMethodType = samMethodBType.toASMType + + def boxInstantiated(instantiatedType: BType, samType: BType): BType = + if(!samType.isPrimitive && instantiatedType.isPrimitive) + boxedClassOfPrimitive(instantiatedType.asPrimitiveBType) + else instantiatedType + // TODO specialization + val instantiatedMethodBType = new MethodBType( + lambdaParamTypes.map(p => toTypeKind(p)), + boxInstantiated(toTypeKind(lambdaTarget.info.resultType), samMethodBType.returnType) + ) + + val instantiatedMethodType = instantiatedMethodBType.toASMType + // scala/bug#10334: make sure that a lambda object for `T => U` has a method `apply(T)U`, not only the `(Object)Object` // version. Using the lambda a structural type `{def apply(t: T): U}` causes a reflective lookup for this method. val needsGenericBridge = samMethodType != instantiatedMethodType