Properly find invoke method on default lambda inlining
In general case parameter type could differ from actual default lambda type.
E.g.: fun inlineFun(s: (Child) -> Base = { a: Base -> a as Child}),
where type of default lambda is '(Base) -> Child'.
In such case we should find somehow actual invoke method in bytecode knowing
only name, number of parameters and that's actual invoke is non-synthetic
regardless of bridge one.
#KT-21946 Fixed
This commit is contained in:
@@ -157,17 +157,18 @@ class DefaultLambda(
|
||||
|
||||
isBoundCallableReference = (isFunctionReference || isPropertyReference) && capturedVars.isNotEmpty()
|
||||
|
||||
invokeMethod = Method(
|
||||
(if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString(),
|
||||
sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor
|
||||
)
|
||||
val methodName = (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString()
|
||||
val signature = sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor
|
||||
|
||||
node = getMethodNode(
|
||||
classReader.b,
|
||||
invokeMethod.name,
|
||||
invokeMethod.descriptor,
|
||||
lambdaClassType
|
||||
) ?: error("Can't find method '${invokeMethod.name}${invokeMethod.descriptor}' in '${classReader.className}'")
|
||||
methodName,
|
||||
signature,
|
||||
lambdaClassType,
|
||||
signatureAmbiguity = true
|
||||
) ?: error("Can't find method '$methodName$signature' in '${classReader.className}'")
|
||||
|
||||
invokeMethod = Method(node.node.name, node.node.desc)
|
||||
|
||||
if (needReification) {
|
||||
//nested classes could also require reification
|
||||
|
||||
@@ -88,7 +88,8 @@ internal fun getMethodNode(
|
||||
classData: ByteArray,
|
||||
methodName: String,
|
||||
methodDescriptor: String,
|
||||
classType: Type
|
||||
classType: Type,
|
||||
signatureAmbiguity: Boolean = false
|
||||
): SMAPAndMethodNode? {
|
||||
val cr = ClassReader(classData)
|
||||
var node: MethodNode? = null
|
||||
@@ -112,17 +113,28 @@ internal fun getMethodNode(
|
||||
signature: String?,
|
||||
exceptions: Array<String>?
|
||||
): MethodVisitor? {
|
||||
if (methodName == name && methodDescriptor == desc) {
|
||||
node = object : MethodNode(Opcodes.API_VERSION, access, name, desc, signature, exceptions) {
|
||||
override fun visitLineNumber(line: Int, start: Label) {
|
||||
super.visitLineNumber(line, start)
|
||||
lines[0] = Math.min(lines[0], line)
|
||||
lines[1] = Math.max(lines[1], line)
|
||||
}
|
||||
if (methodName != name || (signatureAmbiguity && access.and(Opcodes.ACC_SYNTHETIC) != 0)) return null
|
||||
|
||||
if (methodDescriptor != desc) {
|
||||
val sameNumberOfParameters = Type.getArgumentTypes(methodDescriptor).size == Type.getArgumentTypes(desc).size
|
||||
if (!signatureAmbiguity || !sameNumberOfParameters) {
|
||||
return null
|
||||
}
|
||||
return node
|
||||
}
|
||||
return null
|
||||
|
||||
node?.let { existing ->
|
||||
throw AssertionError("Can't find proper '$name' method for inline: ambiguity between '${existing.name + existing.desc}' and '${name + desc}'")
|
||||
}
|
||||
|
||||
return object : MethodNode(Opcodes.API_VERSION, access, name, desc, signature, exceptions) {
|
||||
override fun visitLineNumber(line: Int, start: Label) {
|
||||
super.visitLineNumber(line, start)
|
||||
lines[0] = Math.min(lines[0], line)
|
||||
lines[1] = Math.max(lines[1], line)
|
||||
}
|
||||
}.also {
|
||||
node = it
|
||||
}
|
||||
}
|
||||
}, ClassReader.SKIP_FRAMES or if (GENERATE_SMAP) 0 else ClassReader.SKIP_DEBUG)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user