Refactor SAM type handling, replace non-approximated arguments with *

This commit is contained in:
Dmitry Petrov
2021-06-17 13:37:19 +03:00
committed by TeamCityServer
parent 4aeabb6b0f
commit c77884f067
23 changed files with 721 additions and 128 deletions
@@ -7,8 +7,6 @@ package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.ir.createParameterDeclarations
import org.jetbrains.kotlin.codegen.JvmSamTypeFactory
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
@@ -60,11 +58,6 @@ open class JvmGeneratorExtensionsImpl(private val generateFacades: Boolean = tru
override fun isPlatformSamType(type: KotlinType): Boolean =
JavaSingleAbstractMethodUtils.isSamType(type)
override fun getSamTypeForValueParameter(
valueParameter: ValueParameterDescriptor,
languageVersionSettings: LanguageVersionSettings
): KotlinType? = JvmSamTypeFactory.createByValueParameter(valueParameter, languageVersionSettings)?.type
companion object Instance : JvmSamConversion()
}
@@ -127,8 +127,10 @@ internal class LambdaMetafactoryArgumentsBuilder(
// Don't try to use indy on SAM types with non-invariant projections because buildFakeOverrideMember doesn't support such supertypes
// (and rightly so: supertypes in Kotlin can't have projections in immediate type arguments). This can happen for example in case
// the SAM type is instantiated with an intersection type in arguments, which is approximated to an out-projection in psi2ir.
if (samType is IrSimpleType && samType.arguments.any { it is IrTypeProjection && it.variance != Variance.INVARIANT })
return null
if (samType is IrSimpleType) {
if (samType.arguments.any { it is IrStarProjection || it is IrTypeProjection && it.variance != Variance.INVARIANT })
return null
}
// Do the hard work of matching Kotlin functional interface hierarchy against LambdaMetafactory constraints.
// Briefly: sometimes we have to force boxing on the primitive and inline class values, sometimes we have to keep them unboxed.
@@ -51,10 +51,7 @@ import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl
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 org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -567,7 +564,7 @@ fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: Ca
val typeSubstitutor = TypeSubstitutor.create(substitutionContext)
for (i in underlyingValueParameters.indices) {
val underlyingValueParameter = underlyingValueParameters[i]
val underlyingValueParameter: ValueParameterDescriptor = underlyingValueParameters[i]
val expectedSamConversionTypesForVararg =
if (expectSamConvertedArgumentToBeAvailableInResolvedCall && resolvedCall is NewResolvedCallImpl<*>) {
@@ -585,7 +582,7 @@ fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: Ca
if (!originalValueParameters[i].type.isFunctionTypeOrSubtype) continue
}
val samKotlinType = samConversion.getSamTypeForValueParameter(underlyingValueParameter, context.languageVersionSettings)
val samKotlinType = getSamTypeForValueParameter(underlyingValueParameter)
?: underlyingValueParameter.varargElementType // If we have a vararg, vararg element type will be taken
?: underlyingValueParameter.type
@@ -645,6 +642,23 @@ fun StatementGenerator.generateSamConversionForValueArgumentsIfRequired(call: Ca
}
}
private fun StatementGenerator.getSamTypeForValueParameter(valueParameter: ValueParameterDescriptor): KotlinType? {
val approximatedSamType = context.samTypeApproximator.getSamTypeForValueParameter(valueParameter)
?: return null
if (!context.extensions.samConversion.isSamType(approximatedSamType))
return null
val classDescriptor = approximatedSamType.constructor.declarationDescriptor
?: throw AssertionError("SAM type is expected to be a class type: $approximatedSamType")
return approximatedSamType.replace(
approximatedSamType.arguments.mapIndexed { index: Int, typeProjection: TypeProjection ->
if (typeProjection.type.constructor.isDenotable)
typeProjection
else
StarProjectionImpl(classDescriptor.typeConstructor.parameters[index])
}
)
}
fun StatementGenerator.pregenerateValueArgumentsUsing(
call: CallBuilder,
resolvedCall: ResolvedCall<*>,
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.backend.common.SamTypeApproximator
import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
@@ -33,10 +34,12 @@ class GeneratorContext(
) : IrGeneratorContext {
internal val callToSubstitutedDescriptorMap = mutableMapOf<IrDeclarationReference, CallableDescriptor>()
// TODO: inject a correct StorageManager instance, or store NotFoundClasses inside ModuleDescriptor
val reflectionTypes = ReflectionTypes(moduleDescriptor, NotFoundClasses(LockBasedStorageManager.NO_LOCKS, moduleDescriptor))
fun IrDeclarationReference.commitSubstituted(descriptor: CallableDescriptor) {
callToSubstitutedDescriptorMap[this] = descriptor
}
// TODO: inject a correct StorageManager instance, or store NotFoundClasses inside ModuleDescriptor
val reflectionTypes = ReflectionTypes(moduleDescriptor, NotFoundClasses(LockBasedStorageManager.NO_LOCKS, moduleDescriptor))
val samTypeApproximator = SamTypeApproximator(moduleDescriptor.builtIns, languageVersionSettings)
}
@@ -8,15 +8,12 @@ package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DescriptorVisibility
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall
import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol
import org.jetbrains.kotlin.ir.util.StubGeneratorExtensions
import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.backend.common.SamTypeFactory
import org.jetbrains.kotlin.config.LanguageVersionSettings
open class GeneratorExtensions : StubGeneratorExtensions() {
open val samConversion: SamConversion
@@ -25,11 +22,6 @@ open class GeneratorExtensions : StubGeneratorExtensions() {
open class SamConversion {
open fun isPlatformSamType(type: KotlinType): Boolean = false
open fun getSamTypeForValueParameter(
valueParameter: ValueParameterDescriptor,
languageVersionSettings: LanguageVersionSettings
): KotlinType? = SamTypeFactory.INSTANCE.createByValueParameter(valueParameter, languageVersionSettings)?.type
companion object Instance : SamConversion()
}