diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/CapturedTypes.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/CapturedTypes.kt new file mode 100644 index 00000000000..356840b5f53 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/CapturedTypes.kt @@ -0,0 +1,56 @@ +package org.jetbrains.kotlin.backend.konan.serialization + +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.* +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.name.* +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.resolve.calls.inference.* + +private val konanInternalPackageName = FqName("konan.internal") +private val fakeCapturedTypeClassName = Name.identifier("FAKE_CAPTURED_TYPE_CLASS") + +internal fun createFakeClass(packageName: FqName, className: Name) + = MutableClassDescriptor( + EmptyPackageFragmentDescriptor( + ErrorUtils.getErrorModule(), + packageName + ), + ClassKind.INTERFACE, + /* isInner = */ false, + /* isExternal = */ false, + className, + SourceElement.NO_SOURCE + ) + +// We do the trick similar to FAKE_CONTINUATION_CLASS_DESCRIPTOR. +// To pack a captured type constructor as a type parameter +// of a fake class. We need it because type serialization +// protobuf is not expressive enough. +private val FAKE_CAPTURED_TYPE_CLASS_DESCRIPTOR + = createFakeClass(konanInternalPackageName, fakeCapturedTypeClassName) + .apply { + modality = Modality.ABSTRACT + visibility = Visibilities.PUBLIC + setTypeParameterDescriptors( + TypeParameterDescriptorImpl + .createWithDefaultBound( + this, Annotations.EMPTY, + false, Variance.IN_VARIANCE, + Name.identifier("Projection"), + /* index = */ 0 + ).let(::listOf) + ) + createTypeConstructor() + } + +internal fun packCapturedType(type: CapturedType): SimpleType = + KotlinTypeFactory.simpleType( + Annotations.EMPTY, + FAKE_CAPTURED_TYPE_CLASS_DESCRIPTOR.typeConstructor, + listOf(type.typeProjection), + nullable = false + ) + +internal fun unpackCapturedType(type: KotlinType) + = createCapturedType(type.arguments.single()) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorDeserializer.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorDeserializer.kt index 36732c13bf5..eb553358306 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorDeserializer.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorDeserializer.kt @@ -17,16 +17,15 @@ package org.jetbrains.kotlin.backend.konan.serialization import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.backend.konan.KonanIrDeserializationException import org.jetbrains.kotlin.backend.konan.descriptors.contributedMethods import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke -import org.jetbrains.kotlin.backend.konan.KonanIrDeserializationException -import org.jetbrains.kotlin.backend.konan.llvm.base64Decode import org.jetbrains.kotlin.backend.konan.llvm.symbolName import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.expressions.IrLoop import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.calls.tasks.* +import org.jetbrains.kotlin.resolve.calls.tasks.createSynthesizedInvokes import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.serialization.KonanIr import org.jetbrains.kotlin.serialization.KonanIr.KotlinDescriptor @@ -130,15 +129,19 @@ internal class IrDescriptorDeserializer(val context: Context, val descriptorIndex = IrDeserializationDescriptorIndex(context.irBuiltIns).map fun deserializeKotlinType(proto: KonanIr.KotlinType): KotlinType { - val index = proto.getIndex() val text = proto.getDebugText() val typeProto = localDeserializer.typeTable[index] val type = localDeserializer.deserializeInlineType(typeProto) if (type.isError) throw KonanIrDeserializationException("Could not deserialize KotlinType: $text $type") - context.log("### deserialized Kotlin Type index=$index, text=$text:\t$type") - return type + val realType = if (proto.isCaptured) { + unpackCapturedType(type) + } else + type + + context.log("### deserialized Kotlin Type index=$index, text=$text:\t$realType") + return realType } fun deserializeLocalDeclaration(proto: KonanLinkData.Descriptor): DeclarationDescriptor { when { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorSerializer.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorSerializer.kt index b0679af29cf..19832904bbd 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorSerializer.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/IrDescriptorSerializer.kt @@ -21,7 +21,8 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptor import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.calls.inference.CapturedType +import org.jetbrains.kotlin.resolve.calls.inference.isCaptured import org.jetbrains.kotlin.serialization.KonanIr import org.jetbrains.kotlin.types.KotlinType @@ -40,10 +41,17 @@ internal class IrDescriptorSerializer( var rootFunction: FunctionDescriptor) { fun serializeKotlinType(type: KotlinType): KonanIr.KotlinType { - val index = this.typeSerializer(type) - val proto = KonanIr.KotlinType.newBuilder() + val isCaptured = type.isCaptured() + val typeToSerialize = if (isCaptured) { + packCapturedType(type as CapturedType) + } else { + type + } + val index = typeSerializer(typeToSerialize) + val proto = KonanIr.KotlinType.newBuilder() .setIndex(index) .setDebugText(type.toString()) + .setIsCaptured(isCaptured) .build() return proto } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIr.proto b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIr.proto index f8d1603a47f..1a752bf1bb6 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIr.proto +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/serialization/KonanIr.proto @@ -44,7 +44,8 @@ message LocalDeclaration { message KotlinType { required int32 index = 1; - optional string debug_text = 2; // TODO: remove me + required bool isCaptured = 2; // TODO: make it a flag set? + optional string debug_text = 3; // TODO: remove me } message Coordinates { @@ -190,6 +191,8 @@ message IrWhile { optional IrExpression body = 4; } +// TODO: we need an extension mechanism to accomodate new +// IR operators in upcoming releases. message IrOperation { oneof operation { IrBlock block = 1; @@ -257,6 +260,8 @@ message IrEnumEntry { optional IrDeclaration corresponding_class = 2; } +// TODO: we need an extension mechanism to accomodate new +// IR operators in upcoming releases. message IrDeclarator { oneof symbol { IrVar variable = 1;