JVM_IR KT-43877 fix generic signatures for SAM-converted lambdas

This commit is contained in:
Dmitry Petrov
2020-12-11 15:41:02 +03:00
parent dc11c2de77
commit b7330a9e14
56 changed files with 1014 additions and 59 deletions
@@ -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 ->