From 5c28762c02de7cca22371285320ce1e09b0dd3ad Mon Sep 17 00:00:00 2001 From: Pavel Kirpichenkov Date: Mon, 18 Jan 2021 19:52:15 +0300 Subject: [PATCH] Fix check for local classes in approximating string table Take local/anonymous classes and their inner classes into account. Simplify approximation: use first available super classifier instead of first super class. This approximation should only happen for private declarations that were not previously approximated by frontend. So basically the only requirement for the approximated types is to be denotable. Note that this only works if the types are not used later. JVM uses a different string table implementatin as it needs exact types of private members for reflection. ^KT-20996 Fixed --- .../serialization/ApproximatingStringTable.kt | 16 +++------- .../library/privateObjects.kt | 29 +++++++++++++++++ .../testsWithJsStdLib/localClassMetadata.kt | 31 ++++++++++++++++++- .../testsWithJsStdLib/localClassMetadata.txt | 3 ++ .../CompileKotlinAgainstCustomBinariesTest.kt | 12 +++++++ .../box/multiModule/localClassMetadata.kt | 30 ++++++++++++++++-- 6 files changed, 106 insertions(+), 15 deletions(-) diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/ApproximatingStringTable.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/ApproximatingStringTable.kt index 1e2f3aa2029..74cc59903b4 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/ApproximatingStringTable.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/ApproximatingStringTable.kt @@ -13,19 +13,11 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers -open class ApproximatingStringTable : StringTableImpl() { +class ApproximatingStringTable : StringTableImpl() { override fun getLocalClassIdReplacement(descriptor: ClassifierDescriptorWithTypeParameters): ClassId? { - return if (descriptor.containingDeclaration is CallableMemberDescriptor) { - val superClassifiers = descriptor.getAllSuperClassifiers() - .mapNotNull { it as ClassifierDescriptorWithTypeParameters } - .filter { it != descriptor } - .toList() - if (superClassifiers.size == 1) { - superClassifiers[0].classId - } else { - val superClass = superClassifiers.find { !DescriptorUtils.isInterface(it) } - superClass?.classId ?: ClassId.topLevel(StandardNames.FqNames.any.toSafe()) - } + return if (DescriptorUtils.isLocal(descriptor)) { + descriptor.getAllSuperClassifiers().firstOrNull()?.classId + ?: ClassId.topLevel(StandardNames.FqNames.any.toSafe()) } else { super.getLocalClassIdReplacement(descriptor) } diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/library/privateObjects.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/library/privateObjects.kt index 39a6c985e45..55d262d7c5b 100644 --- a/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/library/privateObjects.kt +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/library/privateObjects.kt @@ -29,6 +29,32 @@ private val o8 = object : G() {} private val o9 = object : G(), I1, I2 {} private val o10 = object : G(), I3 {} +private val o11 = object { + inner class D { + fun df() {} + } + fun d(): D = D() +}.d() + +private val o12 = { + class L { + fun l() {} + } + L() +}() + +private val o13 = { + class L { + inner class L1 { + inner class L2 { + fun l2() {} + } + } + } + + L().L1().L2() +}() + fun fn() { o1.foo() o2.i1() @@ -50,6 +76,9 @@ fun fn() { o10.g() o10.i1() o10.i2() + o11.df() + o12.l() + o13.l2() } class W { diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.kt b/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.kt index a39f6766b27..1c4b22865c7 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.kt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.kt @@ -39,6 +39,32 @@ class C { fun x() = "OK" } + + private val propOI = object { + inner class D { + fun df() {} + } + fun d(): D = D() + }.d() + + private val propL = run { + class L { + fun l() = "propL.l" + } + L() + } + + private val propL2 = run { + class L { + inner class L1 { + inner class L2 { + fun l2() = "propL2.l2" + } + } + } + + L().L1().L2() + } } // MODULE: main(lib) @@ -48,4 +74,7 @@ fun test() { println(C().propI.x()) println(C().propAI.x()) println(C().propG.x()) -} \ No newline at end of file + println(C().propOI.df()) + println(C().propL.l()) + println(C().propL2.l2()) +} diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.txt b/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.txt index eeb8d79f136..33feed2c9e3 100644 --- a/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.txt +++ b/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.txt @@ -15,6 +15,9 @@ public final class C { private final val propAI: C.propAI. private final val propG: C.propG. private final val propI: C.propI. + private final val propL: C.propL..L + private final val propL2: C.propL2..L.L1.L2 + private final val propOI: C.propOI..D public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt index b9cc2e1570e..cc10adc2fac 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt @@ -735,6 +735,18 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration listOf(library), K2MetadataCompiler(), ) + + val klibLibrary = compileCommonLibrary( + libraryName = "library", + listOf("-Xexpect-actual-linker"), + ) + compileKotlin( + "anonymousObjectTypeMetadata.kt", + tmpdir, + listOf(klibLibrary), + K2MetadataCompiler(), + listOf("-Xexpect-actual-linker") + ) } private fun loadClassFile(className: String, dir: File, library: File) { diff --git a/js/js.translator/testData/box/multiModule/localClassMetadata.kt b/js/js.translator/testData/box/multiModule/localClassMetadata.kt index 7d42e42e487..0e509b1e350 100644 --- a/js/js.translator/testData/box/multiModule/localClassMetadata.kt +++ b/js/js.translator/testData/box/multiModule/localClassMetadata.kt @@ -34,14 +34,40 @@ class C { override fun baz() = "propG.baz" } - fun test() = "${propA.bar()};${propI.foo()};${propAI.foo()};${propAI.bar()};${propG.baz()}" + private val propInner = object { + inner class D { + fun df() = "propInner.df" + } + fun d(): D = D() + }.d() + + private val propL = run { + class L { + fun l() = "propL.l" + } + L() + } + + private val propL2 = run { + class L { + inner class L1 { + inner class L2 { + fun l2() = "propL2.l2" + } + } + } + + L().L1().L2() + } + + fun test() = "${propA.bar()};${propI.foo()};${propAI.foo()};${propAI.bar()};${propG.baz()};${propInner.df()};${propL.l()};${propL2.l2()}" } // MODULE: main(lib) // FILE: main.kt fun box(): String { val result = C().test() - if (result != "propA.bar;propI.foo;propAI.foo;propAI.bar;propG.baz") return "fail: $result" + if (result != "propA.bar;propI.foo;propAI.foo;propAI.bar;propG.baz;propInner.df;propL.l;propL2.l2") return "fail: $result" return "OK" } \ No newline at end of file