Approximate types for lambda literals before serialization
This commit is contained in:
@@ -259,7 +259,9 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
Method method = v.getSerializationBindings().get(METHOD_FOR_FUNCTION, frontendFunDescriptor);
|
||||
assert method != null : "No method for " + frontendFunDescriptor;
|
||||
|
||||
FunctionDescriptor freeLambdaDescriptor = FakeDescriptorsForReferencesKt.createFreeFakeLambdaDescriptor(frontendFunDescriptor);
|
||||
FunctionDescriptor freeLambdaDescriptor = FakeDescriptorsForReferencesKt.createFreeFakeLambdaDescriptor(
|
||||
frontendFunDescriptor, state.getTypeApproximator()
|
||||
);
|
||||
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, freeLambdaDescriptor, method);
|
||||
|
||||
DescriptorSerializer serializer =
|
||||
|
||||
@@ -727,7 +727,9 @@ class CoroutineCodegenForNamedFunction private constructor(
|
||||
writeKotlinMetadata(v, state, KotlinClassHeader.Kind.SYNTHETIC_CLASS, 0) { av ->
|
||||
val serializer = DescriptorSerializer.createForLambda(JvmSerializerExtension(v.serializationBindings, state))
|
||||
val functionProto =
|
||||
serializer.functionProto(createFreeFakeLambdaDescriptor(suspendFunctionJvmView))?.build() ?: return@writeKotlinMetadata
|
||||
serializer.functionProto(
|
||||
createFreeFakeLambdaDescriptor(suspendFunctionJvmView, state.typeApproximator)
|
||||
)?.build() ?: return@writeKotlinMetadata
|
||||
AsmUtil.writeAnnotationData(av, serializer, functionProto)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,22 +17,20 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.*
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Given a function descriptor, creates another function descriptor with type parameters copied from outer context(s).
|
||||
* This is needed because once we're serializing this to a proto, there's no place to store information about external type parameters.
|
||||
*/
|
||||
fun createFreeFakeLambdaDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor {
|
||||
return createFreeDescriptor(descriptor)
|
||||
fun createFreeFakeLambdaDescriptor(descriptor: FunctionDescriptor, typeApproximator: TypeApproximator?): FunctionDescriptor {
|
||||
return createFreeDescriptor(descriptor, typeApproximator)
|
||||
}
|
||||
|
||||
private fun <D : CallableMemberDescriptor> createFreeDescriptor(descriptor: D): D {
|
||||
private fun <D : CallableMemberDescriptor> createFreeDescriptor(descriptor: D, typeApproximator: TypeApproximator?): D {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val builder = descriptor.newCopyBuilder() as CallableMemberDescriptor.CopyBuilder<D>
|
||||
|
||||
@@ -49,7 +47,76 @@ private fun <D : CallableMemberDescriptor> createFreeDescriptor(descriptor: D):
|
||||
container = container.containingDeclaration
|
||||
}
|
||||
|
||||
return if (typeParameters.isEmpty()) descriptor else builder.build()!!
|
||||
val approximated = typeApproximator?.approximate(descriptor, builder) ?: false
|
||||
|
||||
return if (typeParameters.isEmpty() && !approximated) descriptor else builder.build()!!
|
||||
}
|
||||
|
||||
private fun TypeApproximator.approximate(descriptor: CallableMemberDescriptor, builder: CallableMemberDescriptor.CopyBuilder<*>): Boolean {
|
||||
var approximated = false
|
||||
|
||||
val returnType = descriptor.returnType
|
||||
if (returnType != null) {
|
||||
// unwrap to avoid instances of DeferredType
|
||||
val approximatedType = approximate(returnType.unwrap(), toSuper = true)
|
||||
if (approximatedType != null) {
|
||||
builder.setReturnType(approximatedType)
|
||||
approximated = true
|
||||
}
|
||||
}
|
||||
|
||||
if (builder !is FunctionDescriptor.CopyBuilder<*>) return approximated
|
||||
|
||||
val extensionReceiverParameter = descriptor.extensionReceiverParameter
|
||||
if (extensionReceiverParameter != null) {
|
||||
val approximatedExtensionReceiver = approximate(extensionReceiverParameter.type.unwrap(), toSuper = false)
|
||||
if (approximatedExtensionReceiver != null) {
|
||||
builder.setExtensionReceiverParameter(
|
||||
extensionReceiverParameter.substituteTopLevelType(approximatedExtensionReceiver)
|
||||
)
|
||||
approximated = true
|
||||
}
|
||||
}
|
||||
|
||||
var valueParameterApproximated = false
|
||||
val newParameters = descriptor.valueParameters.map {
|
||||
val approximatedType = approximate(it.type.unwrap(), toSuper = false)
|
||||
if (approximatedType != null) {
|
||||
valueParameterApproximated = true
|
||||
// invoking constructor explicitly as substitution on value parameters is not supported
|
||||
ValueParameterDescriptorImpl(
|
||||
it.containingDeclaration, it.original, it.index, it.annotations,
|
||||
it.name, outType = approximatedType, it.declaresDefaultValue(),
|
||||
it.isCrossinline, it.isNoinline, it.varargElementType, it.source
|
||||
)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
if (valueParameterApproximated) {
|
||||
builder.setValueParameters(newParameters)
|
||||
approximated = true
|
||||
}
|
||||
|
||||
return approximated
|
||||
}
|
||||
|
||||
private fun ReceiverParameterDescriptor.substituteTopLevelType(newType: KotlinType): ReceiverParameterDescriptor? {
|
||||
val wrappedSubstitution = object : TypeSubstitution() {
|
||||
override fun get(key: KotlinType): TypeProjection? = null
|
||||
override fun prepareTopLevelType(topLevelType: KotlinType, position: Variance): KotlinType = newType
|
||||
}
|
||||
|
||||
return substitute(TypeSubstitutor.create(wrappedSubstitution))
|
||||
}
|
||||
|
||||
private fun TypeApproximator.approximate(type: UnwrappedType, toSuper: Boolean): KotlinType? {
|
||||
if (type.arguments.isEmpty() && type.constructor.isDenotable) return null
|
||||
return if (toSuper)
|
||||
approximateToSuperType(type, TypeApproximatorConfiguration.PublicDeclaration)
|
||||
else
|
||||
approximateToSubType(type, TypeApproximatorConfiguration.PublicDeclaration)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,7 +124,7 @@ private fun <D : CallableMemberDescriptor> createFreeDescriptor(descriptor: D):
|
||||
* when using reflection on that local variable at runtime.
|
||||
* Only members used by [DescriptorSerializer.propertyProto] are implemented correctly in this property descriptor.
|
||||
*/
|
||||
fun createFreeFakeLocalPropertyDescriptor(descriptor: LocalVariableDescriptor): PropertyDescriptor {
|
||||
fun createFreeFakeLocalPropertyDescriptor(descriptor: LocalVariableDescriptor, typeApproximator: TypeApproximator?): PropertyDescriptor {
|
||||
val property = PropertyDescriptorImpl.create(
|
||||
descriptor.containingDeclaration, descriptor.annotations, Modality.FINAL, descriptor.visibility, descriptor.isVar,
|
||||
descriptor.name, CallableMemberDescriptor.Kind.DECLARATION, descriptor.source, false, descriptor.isConst,
|
||||
@@ -83,5 +150,5 @@ fun createFreeFakeLocalPropertyDescriptor(descriptor: LocalVariableDescriptor):
|
||||
}
|
||||
)
|
||||
|
||||
return createFreeDescriptor(property)
|
||||
return createFreeDescriptor(property, typeApproximator)
|
||||
}
|
||||
|
||||
+2
-1
@@ -58,6 +58,7 @@ class JvmSerializerExtension @JvmOverloads constructor(
|
||||
private val functionsWithInlineClassReturnTypesMangled = state.functionsWithInlineClassReturnTypesMangled
|
||||
override val metadataVersion = state.metadataVersion
|
||||
private val jvmDefaultMode = state.jvmDefaultMode
|
||||
private val approximator = state.typeApproximator
|
||||
|
||||
override fun shouldUseTypeTable(): Boolean = useTypeTable
|
||||
override fun shouldSerializeFunction(descriptor: FunctionDescriptor): Boolean {
|
||||
@@ -137,7 +138,7 @@ class JvmSerializerExtension @JvmOverloads constructor(
|
||||
val localVariables = CodegenBinding.getLocalDelegatedProperties(codegenBinding, classAsmType) ?: return
|
||||
|
||||
for (localVariable in localVariables) {
|
||||
val propertyDescriptor = createFreeFakeLocalPropertyDescriptor(localVariable)
|
||||
val propertyDescriptor = createFreeFakeLocalPropertyDescriptor(localVariable, approximator)
|
||||
val serializer = DescriptorSerializer.createForLambda(this)
|
||||
proto.addExtension(extension, serializer.propertyProto(propertyDescriptor)?.build() ?: continue)
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind.*
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeApproximator
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import java.io.File
|
||||
@@ -285,6 +286,12 @@ class GenerationState private constructor(
|
||||
lateinit var irBasedMapAsmMethod: (FunctionDescriptor) -> Method
|
||||
var mapInlineClass: (ClassDescriptor) -> Type = { descriptor -> typeMapper.mapType(descriptor.defaultType) }
|
||||
|
||||
val typeApproximator: TypeApproximator? =
|
||||
if (languageVersionSettings.supportsFeature(LanguageFeature.NewInference))
|
||||
TypeApproximator(module.builtIns)
|
||||
else
|
||||
null
|
||||
|
||||
init {
|
||||
this.interceptedBuilderFactory = builderFactory
|
||||
.wrapWith(
|
||||
|
||||
Reference in New Issue
Block a user