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:
Dmitry Petrov
2019-08-13 12:23:15 +03:00
parent 6b208f7c9c
commit 986654b709
20 changed files with 658 additions and 47 deletions
@@ -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()
@@ -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)
}
@@ -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()
}
@@ -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 -> {