From f5a53c82c568fc071741d410e7eea6fd81070a14 Mon Sep 17 00:00:00 2001 From: Pavel Kirpichenkov Date: Tue, 18 May 2021 12:02:56 +0300 Subject: [PATCH] Don't write type arguments of types replaced with Any to metadata Anonymous types are not approximated by frontend for private declarations. Class IDs for such types are replaced by StringTable before being written to metadata. JVM string table mangles such types and keeps them generic for reflection. For other purposes the types are replaced with `Any`. Type arguments of the replaced type should be ignored in the latter case. Otherwise decompiled text builder crashes on an attempt to restore `Any` type with non-zero number of type arguments. The code pretending to replace a type with its first supertype was dropped from ApproximatingStringTable for two reasons: - the first type from `getAllSuperClassifiers` is the original type itself which doens't provide a ClassId for anonymous type, so it was a noop - tracking potential type arguments of the first anonymous type's supertype would be a complication with almost no practical value (types in decompiled text would be slightly closer to the real type of a private declaration). ^KT-46393 Fixed --- .../codegen/serialization/JvmCodegenStringTable.kt | 3 +++ .../kotlin/serialization/ApproximatingStringTable.kt | 9 ++++----- .../kotlin/serialization/DescriptorAwareStringTable.kt | 8 ++++++++ .../kotlin/serialization/DescriptorSerializer.kt | 8 ++++++-- .../jetbrains/kotlin/serialization/StringTableImpl.kt | 3 +++ .../LocalClassAsTypeWithArgument/directives.txt | 2 -- 6 files changed, 24 insertions(+), 9 deletions(-) delete mode 100644 idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/directives.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmCodegenStringTable.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmCodegenStringTable.kt index 857a6bcd16a..f317ed918c6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmCodegenStringTable.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/serialization/JvmCodegenStringTable.kt @@ -29,4 +29,7 @@ class JvmCodegenStringTable @JvmOverloads constructor( ClassId(fqName.parent(), FqName.topLevel(fqName.shortName()), true) } } + + override val isLocalClassIdReplacementKeptGeneric: Boolean + get() = true } diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/ApproximatingStringTable.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/ApproximatingStringTable.kt index 74cc59903b4..d69f230966f 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/ApproximatingStringTable.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/ApproximatingStringTable.kt @@ -6,20 +6,19 @@ package org.jetbrains.kotlin.serialization import org.jetbrains.kotlin.builtins.StandardNames -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.descriptorUtil.classId -import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers class ApproximatingStringTable : StringTableImpl() { override fun getLocalClassIdReplacement(descriptor: ClassifierDescriptorWithTypeParameters): ClassId? { return if (DescriptorUtils.isLocal(descriptor)) { - descriptor.getAllSuperClassifiers().firstOrNull()?.classId - ?: ClassId.topLevel(StandardNames.FqNames.any.toSafe()) + ClassId.topLevel(StandardNames.FqNames.any.toSafe()) } else { super.getLocalClassIdReplacement(descriptor) } } + + override val isLocalClassIdReplacementKeptGeneric: Boolean + get() = false } diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorAwareStringTable.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorAwareStringTable.kt index 55cdd67748c..00b73ed0d40 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorAwareStringTable.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorAwareStringTable.kt @@ -30,6 +30,14 @@ interface DescriptorAwareStringTable : StringTable { fun getLocalClassIdReplacement(descriptor: ClassifierDescriptorWithTypeParameters): ClassId? = null + /** + * true if this [StringTable] replaces absent [ClassId] of a local class descriptor with a semantic equivalent that + * still expects original type arguments when used in a type + * false otherwise + */ + val isLocalClassIdReplacementKeptGeneric: Boolean + get() = false + private fun renderDescriptor(descriptor: ClassifierDescriptorWithTypeParameters): String = DescriptorRenderer.COMPACT.render(descriptor) + " defined in " + DescriptorRenderer.FQ_NAMES_IN_TYPES.render(descriptor.containingDeclaration) diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt index 24b58bb01a2..8b0fd6052e9 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.kt @@ -671,13 +671,17 @@ class DescriptorSerializer private constructor( private fun fillFromPossiblyInnerType(builder: ProtoBuf.Type.Builder, type: PossiblyInnerType) { val classifierDescriptor = type.classifierDescriptor val classifierId = getClassifierId(classifierDescriptor) + when (classifierDescriptor) { is ClassDescriptor -> builder.className = classifierId is TypeAliasDescriptor -> builder.typeAliasName = classifierId } - for (projection in type.arguments) { - builder.addArgument(typeArgument(projection)) + // Shouldn't write type parameters of a generic local anonymous type if it was replaced with Any + if (stringTable.isLocalClassIdReplacementKeptGeneric || !DescriptorUtils.isLocal(classifierDescriptor)) { + for (projection in type.arguments) { + builder.addArgument(typeArgument(projection)) + } } if (type.outerType != null) { diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/StringTableImpl.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/StringTableImpl.kt index 486afbff2ee..423ca071adf 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/StringTableImpl.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/StringTableImpl.kt @@ -89,4 +89,7 @@ open class StringTableImpl : DescriptorAwareStringTable { return Pair(strings.build(), qualifiedNames.build()) } + + override val isLocalClassIdReplacementKeptGeneric: Boolean + get() = false } diff --git a/idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/directives.txt b/idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/directives.txt deleted file mode 100644 index 0d65498a97d..00000000000 --- a/idea/testData/decompiler/decompiledText/LocalClassAsTypeWithArgument/directives.txt +++ /dev/null @@ -1,2 +0,0 @@ -// TODO: See KT-13618 -// IGNORE_BACKEND: JS