psi2ir: fix unsubstituted type parameters around SAM conversions
Preserve type substitution: - when obtaining function type for SAM type; - when generating SAM conversions for SAM adapter arguments; - for "original" method corresponding to a SAM adapter.
This commit is contained in:
+7
-9
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
||||
@@ -16,7 +15,7 @@ import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
|
||||
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
|
||||
import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.*
|
||||
|
||||
object JvmGeneratorExtensions : GeneratorExtensions() {
|
||||
override val externalDeclarationOrigin: ((DeclarationDescriptor) -> IrDeclarationOrigin)? = { descriptor ->
|
||||
@@ -43,15 +42,14 @@ object JvmGeneratorExtensions : GeneratorExtensions() {
|
||||
override fun isSamType(type: KotlinType): Boolean =
|
||||
SingleAbstractMethodUtils.isSamType(type)
|
||||
|
||||
override fun getFunctionTypeForSAMClass(descriptor: ClassDescriptor): KotlinType {
|
||||
if (descriptor !is JavaClassDescriptor) {
|
||||
throw AssertionError("SAM should be represented by a Java class: $descriptor")
|
||||
}
|
||||
|
||||
override fun getSubstitutedFunctionTypeForSamType(samType: KotlinType): KotlinType {
|
||||
val descriptor = samType.constructor.declarationDescriptor as? JavaClassDescriptor
|
||||
?: throw AssertionError("SAM should be represented by a Java class: $samType")
|
||||
val singleAbstractMethod = SingleAbstractMethodUtils.getSingleAbstractMethodOrNull(descriptor)
|
||||
?: throw AssertionError("$descriptor should have a single abstract method")
|
||||
|
||||
return SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(singleAbstractMethod, false)
|
||||
val unsubstitutedFunctionType = SingleAbstractMethodUtils.getFunctionTypeForAbstractMethod(singleAbstractMethod, false)
|
||||
return TypeSubstitutor.create(samType).substitute(unsubstitutedFunctionType, Variance.INVARIANT)
|
||||
?: throw AssertionError("Failed to substitute function type $unsubstitutedFunctionType corresponding to $samType")
|
||||
}
|
||||
|
||||
companion object Instance : JvmSamConversion()
|
||||
|
||||
+45
-20
@@ -41,7 +41,9 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
@@ -292,17 +294,9 @@ fun StatementGenerator.generateValueArgumentUsing(
|
||||
TODO("Unexpected valueArgument: ${valueArgument::class.java.simpleName}")
|
||||
}
|
||||
|
||||
fun StatementGenerator.castArgumentToFunctionalInterfaceForSamType(
|
||||
irExpression: IrExpression,
|
||||
samType: KotlinType
|
||||
): IrExpression {
|
||||
val samConversion = context.extensions.samConversion
|
||||
val samTypeDescriptor = samType.constructor.declarationDescriptor
|
||||
val samClassDescriptor = samTypeDescriptor as? ClassDescriptor
|
||||
?: throw AssertionError("SAM class expected: $samType")
|
||||
val kotlinFunctionType = samConversion.getFunctionTypeForSAMClass(samClassDescriptor)
|
||||
fun StatementGenerator.castArgumentToFunctionalInterfaceForSamType(irExpression: IrExpression, samType: KotlinType): IrExpression {
|
||||
val kotlinFunctionType = context.extensions.samConversion.getSubstitutedFunctionTypeForSamType(samType)
|
||||
val irFunctionType = context.typeTranslator.translateType(kotlinFunctionType)
|
||||
|
||||
return irExpression.implicitCastTo(irFunctionType)
|
||||
}
|
||||
|
||||
@@ -422,6 +416,16 @@ fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: Ca
|
||||
"Mismatching value parameters, $originalDescriptor vs call: " +
|
||||
"${originalValueParameters.size} != ${call.argumentsCount}"
|
||||
}
|
||||
assert(underlyingDescriptor.typeParameters.size == originalDescriptor.typeParameters.size) {
|
||||
"Mismatching type parameters:\n" +
|
||||
"$underlyingDescriptor has ${underlyingDescriptor.typeParameters}\n" +
|
||||
"$originalDescriptor has ${originalDescriptor.typeParameters}"
|
||||
}
|
||||
|
||||
val substitutionContext = call.original.typeArguments.entries.associate { (typeParameterDescriptor, typeArgument) ->
|
||||
underlyingDescriptor.typeParameters[typeParameterDescriptor.index].typeConstructor to TypeProjectionImpl(typeArgument)
|
||||
}
|
||||
val typeSubstitutor = TypeSubstitutor.create(substitutionContext)
|
||||
|
||||
for (i in underlyingValueParameters.indices) {
|
||||
val originalParameterType = originalValueParameters[i].type
|
||||
@@ -432,7 +436,13 @@ fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: Ca
|
||||
|
||||
val originalArgument = call.irValueArgumentsByIndex[i] ?: continue
|
||||
|
||||
val targetType = underlyingParameterType.toIrType()
|
||||
val expectedArgumentType = typeSubstitutor.substitute(underlyingParameterType, Variance.INVARIANT)
|
||||
?: throw AssertionError(
|
||||
"Failed to substitute value argument type in SAM conversion: " +
|
||||
"underlyingParameterType=$underlyingParameterType, " +
|
||||
"substitutionContext=$substitutionContext"
|
||||
)
|
||||
val targetType = expectedArgumentType.toIrType()
|
||||
|
||||
call.irValueArgumentsByIndex[i] =
|
||||
IrTypeOperatorCallImpl(
|
||||
@@ -440,7 +450,7 @@ fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: Ca
|
||||
targetType,
|
||||
IrTypeOperator.SAM_CONVERSION,
|
||||
targetType,
|
||||
castArgumentToFunctionalInterfaceForSamType(originalArgument, underlyingParameterType)
|
||||
castArgumentToFunctionalInterfaceForSamType(originalArgument, expectedArgumentType)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -477,9 +487,12 @@ private fun unwrapSpecialDescriptor(
|
||||
samConversion: GeneratorExtensions.SamConversion
|
||||
): CallableDescriptor =
|
||||
when (descriptor) {
|
||||
is ImportedFromObjectCallableDescriptor<*> -> unwrapSpecialDescriptor(descriptor.callableFromObject, samConversion)
|
||||
is TypeAliasConstructorDescriptor -> descriptor.underlyingConstructorDescriptor
|
||||
else -> samConversion.getOriginalForSamAdapter(descriptor)?.let { unwrapSpecialDescriptor(it, samConversion) } ?: descriptor
|
||||
is ImportedFromObjectCallableDescriptor<*> ->
|
||||
unwrapSpecialDescriptor(descriptor.callableFromObject, samConversion)
|
||||
is TypeAliasConstructorDescriptor ->
|
||||
descriptor.underlyingConstructorDescriptor
|
||||
else ->
|
||||
samConversion.getOriginalForSamAdapter(descriptor)?.let { unwrapSpecialDescriptor(it, samConversion) } ?: descriptor
|
||||
}
|
||||
|
||||
fun unwrapCallableDescriptorAndTypeArguments(resolvedCall: ResolvedCall<*>, samConversion: GeneratorExtensions.SamConversion): CallBuilder {
|
||||
@@ -503,11 +516,11 @@ fun unwrapCallableDescriptorAndTypeArguments(resolvedCall: ResolvedCall<*>, samC
|
||||
if (unsubstitutedUnwrappedTypeParameters.isEmpty())
|
||||
null
|
||||
else
|
||||
unsubstitutedUnwrappedTypeParameters.associate {
|
||||
unsubstitutedUnwrappedTypeParameters.associateWith {
|
||||
val originalTypeParameter = candidateDescriptor.typeParameters[it.index]
|
||||
val originalTypeArgument = originalTypeArguments[originalTypeParameter]
|
||||
?: throw AssertionError("No type argument for $originalTypeParameter")
|
||||
it to originalTypeArgument
|
||||
originalTypeArgument
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,8 +529,8 @@ fun unwrapCallableDescriptorAndTypeArguments(resolvedCall: ResolvedCall<*>, samC
|
||||
if (substitutedType.arguments.isEmpty())
|
||||
null
|
||||
else
|
||||
unsubstitutedUnwrappedTypeParameters.associate {
|
||||
it to substitutedType.arguments[it.index].type
|
||||
unsubstitutedUnwrappedTypeParameters.associateWith {
|
||||
substitutedType.arguments[it.index].type
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,5 +560,17 @@ fun unwrapCallableDescriptorAndTypeArguments(resolvedCall: ResolvedCall<*>, samC
|
||||
}
|
||||
}
|
||||
|
||||
return CallBuilder(resolvedCall, unwrappedDescriptor, unwrappedTypeArguments)
|
||||
val substitutedUnwrappedDescriptor =
|
||||
if (unwrappedTypeArguments == null)
|
||||
unwrappedDescriptor
|
||||
else {
|
||||
val substitutionContext = unsubstitutedUnwrappedDescriptor.typeParameters.associate {
|
||||
val typeArgument = unwrappedTypeArguments[it]
|
||||
?: throw AssertionError("No type argument for $it in $unwrappedTypeArguments")
|
||||
it.typeConstructor to TypeProjectionImpl(typeArgument)
|
||||
}
|
||||
unwrappedDescriptor.substitute(TypeSubstitutor.create(substitutionContext))
|
||||
}
|
||||
|
||||
return CallBuilder(resolvedCall, substitutedUnwrappedDescriptor, unwrappedTypeArguments)
|
||||
}
|
||||
|
||||
+3
-2
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
|
||||
open class GeneratorExtensions {
|
||||
open val externalDeclarationOrigin: ((DeclarationDescriptor) -> IrDeclarationOrigin)?
|
||||
@@ -26,8 +27,8 @@ open class GeneratorExtensions {
|
||||
|
||||
open fun isSamType(type: KotlinType): Boolean = false
|
||||
|
||||
open fun getFunctionTypeForSAMClass(descriptor: ClassDescriptor): KotlinType =
|
||||
throw UnsupportedOperationException("SAM conversion is not supported in this configuration (class=$descriptor)")
|
||||
open fun getSubstitutedFunctionTypeForSamType(samType: KotlinType): KotlinType =
|
||||
throw UnsupportedOperationException("SAM conversion is not supported in this configuration (samType=$samType)")
|
||||
|
||||
companion object Instance : SamConversion()
|
||||
}
|
||||
|
||||
+1
-5
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.psi2ir.transformations
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
@@ -32,7 +31,6 @@ import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.TypeTranslator
|
||||
import org.jetbrains.kotlin.ir.util.coerceToUnitIfNeeded
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.psi2ir.containsNull
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
|
||||
@@ -181,9 +179,7 @@ open class InsertImplicitCasts(
|
||||
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression =
|
||||
when (expression.operator) {
|
||||
IrTypeOperator.SAM_CONVERSION -> expression.transformPostfix {
|
||||
val targetClassDescriptor = typeOperandClassifier.descriptor as? ClassDescriptor
|
||||
?: throw AssertionError("Target type of $operator should be a class: ${render()}")
|
||||
argument = argument.cast(samConversion.getFunctionTypeForSAMClass(targetClassDescriptor))
|
||||
argument = argument.cast(samConversion.getSubstitutedFunctionTypeForSamType(typeOperand.originalKotlinType!!))
|
||||
}
|
||||
|
||||
IrTypeOperator.IMPLICIT_CAST -> {
|
||||
|
||||
Reference in New Issue
Block a user