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
This commit is contained in:
Pavel Kirpichenkov
2021-05-18 12:02:56 +03:00
committed by Space
parent fefc6f9b53
commit f5a53c82c5
6 changed files with 24 additions and 9 deletions
@@ -29,4 +29,7 @@ class JvmCodegenStringTable @JvmOverloads constructor(
ClassId(fqName.parent(), FqName.topLevel(fqName.shortName()), true)
}
}
override val isLocalClassIdReplacementKeptGeneric: Boolean
get() = true
}
@@ -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
}
@@ -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)
@@ -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) {
@@ -89,4 +89,7 @@ open class StringTableImpl : DescriptorAwareStringTable {
return Pair(strings.build(), qualifiedNames.build())
}
override val isLocalClassIdReplacementKeptGeneric: Boolean
get() = false
}
@@ -1,2 +0,0 @@
// TODO: See KT-13618
// IGNORE_BACKEND: JS