JVM_IR KT-43877 fix generic signatures for SAM-converted lambdas
This commit is contained in:
+36
-5
@@ -159,8 +159,8 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
private val adaptedReferenceOriginalTarget: IrFunction? = adapteeCall?.symbol?.owner
|
||||
private val isAdaptedReference = adaptedReferenceOriginalTarget != null
|
||||
|
||||
private val isKotlinFunInterface =
|
||||
samSuperType != null && samSuperType.getClass()?.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
|
||||
private val samInterface = samSuperType?.getClass()
|
||||
private val isKotlinFunInterface = samInterface != null && !samInterface.isFromJava()
|
||||
|
||||
private val needToGenerateSamEqualsHashCodeMethods =
|
||||
isKotlinFunInterface && (isAdaptedReference || !isLambda)
|
||||
@@ -196,6 +196,14 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
context.ir.symbols.functionAdapter.defaultType
|
||||
else null,
|
||||
)
|
||||
if (samInterface != null && origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL) {
|
||||
// Old back-end generates formal type parameters as in SAM supertype.
|
||||
// Here we create formal type parameters with same names and equivalent upper bounds.
|
||||
// We don't really perform any type substitutions within class body
|
||||
// (it's all fine as soon as we have required generic signatures and don't fail anywhere).
|
||||
// NB this would no longer matter if we generate SAM wrapper classes as synthetic.
|
||||
typeParameters = createFakeFormalTypeParameters(samInterface.typeParameters, this)
|
||||
}
|
||||
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
copyAttributes(irFunctionReference)
|
||||
if (isLambda) {
|
||||
@@ -203,6 +211,24 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFakeFormalTypeParameters(sourceTypeParameters: List<IrTypeParameter>, irClass: IrClass): List<IrTypeParameter> {
|
||||
if (sourceTypeParameters.isEmpty()) return emptyList()
|
||||
|
||||
val fakeTypeParameters = sourceTypeParameters.map {
|
||||
buildTypeParameter(irClass) {
|
||||
updateFrom(it)
|
||||
name = it.name
|
||||
}
|
||||
}
|
||||
val typeRemapper = IrTypeParameterRemapper(sourceTypeParameters.associateWith { fakeTypeParameters[it.index] })
|
||||
for (fakeTypeParameter in fakeTypeParameters) {
|
||||
val sourceTypeParameter = sourceTypeParameters[fakeTypeParameter.index]
|
||||
fakeTypeParameter.superTypes = sourceTypeParameter.superTypes.map { typeRemapper.remapType(it) }
|
||||
}
|
||||
|
||||
return fakeTypeParameters
|
||||
}
|
||||
|
||||
private val receiverField = context.ir.symbols.functionReferenceReceiverField.owner
|
||||
|
||||
fun build(): IrExpression = context.createJvmIrBuilder(currentScope!!.scope.scopeOwnerSymbol).run {
|
||||
@@ -390,7 +416,11 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
isSuspend = callee.isSuspend
|
||||
}.apply {
|
||||
overriddenSymbols += superMethod
|
||||
dispatchReceiverParameter = parentAsClass.thisReceiver!!.copyTo(this)
|
||||
dispatchReceiverParameter = buildReceiverParameter(
|
||||
this,
|
||||
IrDeclarationOrigin.INSTANCE_RECEIVER,
|
||||
functionReferenceClass.symbol.defaultType
|
||||
)
|
||||
if (isLambda) createLambdaInvokeMethod() else createFunctionReferenceInvokeMethod(receiverVar)
|
||||
}
|
||||
|
||||
@@ -427,8 +457,9 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
|
||||
// will put it into a field.
|
||||
if (samSuperType == null)
|
||||
irImplicitCast(
|
||||
irGetField(irGet(dispatchReceiverParameter!!),
|
||||
this@FunctionReferenceBuilder.receiverField
|
||||
irGetField(
|
||||
irGet(dispatchReceiverParameter!!),
|
||||
this@FunctionReferenceBuilder.receiverField
|
||||
),
|
||||
boundReceiver.second.type
|
||||
)
|
||||
|
||||
@@ -1075,11 +1075,13 @@ private fun makeKotlinType(
|
||||
classDescriptor.defaultType.replace(newArguments = kotlinTypeArguments).makeNullableAsSpecified(hasQuestionMark)
|
||||
} catch (e: Throwable) {
|
||||
throw RuntimeException(
|
||||
"Classifier: $classDescriptor\n" +
|
||||
"Classifier: ${classifier.owner.render()}\n" +
|
||||
"Type parameters:\n" +
|
||||
classDescriptor.defaultType.constructor.parameters.withIndex()
|
||||
.joinToString(separator = "\n") {
|
||||
"${it.index}: ${(it.value as IrBasedTypeParameterDescriptor).owner.render()}"
|
||||
val irTypeParameter = (it.value as IrBasedTypeParameterDescriptor).owner
|
||||
"${it.index}: ${irTypeParameter.render()} " +
|
||||
"of ${irTypeParameter.parent.render()}"
|
||||
} +
|
||||
"\nType arguments:\n" +
|
||||
arguments.withIndex()
|
||||
|
||||
@@ -18,8 +18,10 @@ import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.impl.*
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.isAnonymousObject
|
||||
import org.jetbrains.kotlin.ir.util.isPropertyAccessor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||
@@ -177,6 +179,10 @@ val IrClass.typeConstructorParameters: Sequence<IrTypeParameter>
|
||||
// Ideally this should be fixed in FE.
|
||||
null
|
||||
}
|
||||
current.isAnonymousObject -> {
|
||||
// Anonymous classes don't capture type parameters.
|
||||
null
|
||||
}
|
||||
parent is IrClass && current is IrClass && !current.isInner ->
|
||||
null
|
||||
else ->
|
||||
|
||||
Reference in New Issue
Block a user