From 2f3f75b512039d05e782e1e810f3275a521814af Mon Sep 17 00:00:00 2001 From: Pavel Kirpichenkov Date: Thu, 14 Jan 2021 18:53:18 +0300 Subject: [PATCH] Fix local anonymous class name error in K2MetadataCompiler Extract the logic of approximating to denotable class supertype from JS/KLIB and use it in metadata compiler. ^KT-20996 In Progress --- .../metadata/MetadataSerializerExtension.kt | 2 + .../serialization/ApproximatingStringTable.kt | 33 +++++ .../cli/metadata/anonymousObjectType.out | 63 +-------- .../anonymousObjectTypeMetadata.kt | 13 ++ .../library/privateObjects.kt | 125 ++++++++++++++++++ .../anonymousObjectTypeMetadata/output.txt | 10 ++ .../CompileKotlinAgainstCustomBinariesTest.kt | 12 ++ .../metadata/KlibMetadataStringTable.kt | 28 +--- .../serialization/js/JavaScriptStringTable.kt | 28 +--- 9 files changed, 200 insertions(+), 114 deletions(-) create mode 100644 compiler/serialization/src/org/jetbrains/kotlin/serialization/ApproximatingStringTable.kt create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/anonymousObjectTypeMetadata.kt create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/library/privateObjects.kt create mode 100644 compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/output.txt diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializerExtension.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializerExtension.kt index c70b687bf59..51fcfdcb1eb 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializerExtension.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/metadata/MetadataSerializerExtension.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.cli.metadata import org.jetbrains.kotlin.metadata.builtins.BuiltInsBinaryVersion +import org.jetbrains.kotlin.serialization.ApproximatingStringTable import org.jetbrains.kotlin.serialization.KotlinSerializerExtensionBase import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol @@ -24,4 +25,5 @@ class MetadataSerializerExtension( override val metadataVersion: BuiltInsBinaryVersion ) : KotlinSerializerExtensionBase(BuiltInSerializerProtocol) { override fun shouldUseTypeTable(): Boolean = true + override val stringTable = ApproximatingStringTable() } diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/ApproximatingStringTable.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/ApproximatingStringTable.kt new file mode 100644 index 00000000000..1e2f3aa2029 --- /dev/null +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/ApproximatingStringTable.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +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 + +open 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()) + } + } else { + super.getLocalClassIdReplacement(descriptor) + } + } +} diff --git a/compiler/testData/cli/metadata/anonymousObjectType.out b/compiler/testData/cli/metadata/anonymousObjectType.out index e1446344b7f..d86bac9de59 100644 --- a/compiler/testData/cli/metadata/anonymousObjectType.out +++ b/compiler/testData/cli/metadata/anonymousObjectType.out @@ -1,62 +1 @@ -exception: java.lang.IllegalStateException: Cannot get FQ name of local class: class defined in private val pVal: defined in root package in file anonymousObjectType.kt - at org.jetbrains.kotlin.serialization.DescriptorAwareStringTable$DefaultImpls.getFqNameIndex(DescriptorAwareStringTable.kt:26) - at org.jetbrains.kotlin.serialization.StringTableImpl.getFqNameIndex(StringTableImpl.kt:25) - at org.jetbrains.kotlin.serialization.DescriptorSerializer.getClassifierId(DescriptorSerializer.kt:741) - at org.jetbrains.kotlin.serialization.DescriptorSerializer.fillFromPossiblyInnerType(DescriptorSerializer.kt:613) - at org.jetbrains.kotlin.serialization.DescriptorSerializer.type$serialization(DescriptorSerializer.kt:580) - at org.jetbrains.kotlin.serialization.DescriptorSerializer.typeId(DescriptorSerializer.kt:547) - at org.jetbrains.kotlin.serialization.DescriptorSerializer.propertyProto(DescriptorSerializer.kt:255) - at org.jetbrains.kotlin.serialization.DescriptorSerializer.packagePartProto(DescriptorSerializer.kt:661) - at org.jetbrains.kotlin.cli.metadata.MetadataSerializer$PackageSerializer.serializeMembers(MetadataSerializer.kt:157) - at org.jetbrains.kotlin.cli.metadata.MetadataSerializer$PackageSerializer.run(MetadataSerializer.kt:136) - at org.jetbrains.kotlin.cli.metadata.MetadataSerializer.performSerialization(MetadataSerializer.kt:94) - at org.jetbrains.kotlin.cli.metadata.MetadataSerializer.serialize(MetadataSerializer.kt:49) - at org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler.doExecute(K2MetadataCompiler.kt:111) - at org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler.doExecute(K2MetadataCompiler.kt:40) - at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:88) - at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:44) - at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:98) - at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:76) - at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:45) - at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMainNoExit(CLITool.kt:227) - at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMainNoExit$default(CLITool.kt:222) - at org.jetbrains.kotlin.test.CompilerTestUtil.executeCompiler(CompilerTestUtil.kt:41) - at org.jetbrains.kotlin.cli.AbstractCliTest.executeCompilerGrabOutput(AbstractCliTest.java:73) - at org.jetbrains.kotlin.cli.AbstractCliTest.doTest(AbstractCliTest.java:105) - at org.jetbrains.kotlin.cli.AbstractCliTest.doMetadataTest(AbstractCliTest.java:285) - at org.jetbrains.kotlin.test.KotlinTestUtils.lambda$testWithCustomIgnoreDirective$5(KotlinTestUtils.java:572) - at org.jetbrains.kotlin.test.KotlinTestUtils.runTestImpl(KotlinTestUtils.java:542) - at org.jetbrains.kotlin.test.KotlinTestUtils.runTest(KotlinTestUtils.java:485) - at org.jetbrains.kotlin.cli.CliTestGenerated$Metadata.runTest(CliTestGenerated.java:1176) - at org.jetbrains.kotlin.cli.CliTestGenerated$Metadata.testAnonymousObjectType(CliTestGenerated.java:1185) - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.lang.reflect.Method.invoke(Method.java:498) - at junit.framework.TestCase.runTest(TestCase.java:176) - at org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase.lambda$runTest$9(KtUsefulTestCase.java:374) - at org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase.lambda$invokeTestRunnable$10(KtUsefulTestCase.java:407) - at com.intellij.testFramework.EdtTestUtilKt.runInEdtAndWait(EdtTestUtil.kt:63) - at org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase.invokeTestRunnable(KtUsefulTestCase.java:406) - at org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase.runTest(KtUsefulTestCase.java:393) - at org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase.defaultRunBare(KtUsefulTestCase.java:424) - at com.intellij.testFramework.EdtTestUtil$Companion$runInEdtAndWait$1.invoke(EdtTestUtil.kt:18) - at com.intellij.testFramework.EdtTestUtil$Companion$runInEdtAndWait$1.invoke(EdtTestUtil.kt:13) - at com.intellij.testFramework.EdtTestUtilKt$runInEdtAndWait$3.run(EdtTestUtil.kt:67) - at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:301) - at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758) - at java.awt.EventQueue.access$500(EventQueue.java:97) - at java.awt.EventQueue$3.run(EventQueue.java:709) - at java.awt.EventQueue$3.run(EventQueue.java:703) - at java.security.AccessController.doPrivileged(Native Method) - at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74) - at java.awt.EventQueue.dispatchEvent(EventQueue.java:728) - at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:419) - at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205) - at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116) - at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105) - at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) - at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93) - at java.awt.EventDispatchThread.run(EventDispatchThread.java:82) - -INTERNAL_ERROR +OK diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/anonymousObjectTypeMetadata.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/anonymousObjectTypeMetadata.kt new file mode 100644 index 00000000000..67f75708502 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/anonymousObjectTypeMetadata.kt @@ -0,0 +1,13 @@ +package test + +import lib.* + +val w = W() +val v1 = fn() +val v2 = O.o() +val v3 = w.w() + +// private +val e1 = o3 +val e2 = w.o7 +val e3 = O.o10 diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/library/privateObjects.kt b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/library/privateObjects.kt new file mode 100644 index 00000000000..39a6c985e45 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/library/privateObjects.kt @@ -0,0 +1,125 @@ +package lib + +interface I1 { + fun i1() {} +} + +interface I2 { + fun i2() {} +} + +interface I3 : I2, I1 + +open class C { + fun c() {} +} + +open class G { + fun g() {} +} + +private val o1 = object { fun foo() {} } +private val o2 = object : I1 {} +private val o3 = object : I1, I2 {} +private val o4 = object : I3 {} +private val o5 = object : C() {} +private val o6 = object : C(), I1, I2 {} +private val o7 = object : C(), I3 {} +private val o8 = object : G() {} +private val o9 = object : G(), I1, I2 {} +private val o10 = object : G(), I3 {} + +fun fn() { + o1.foo() + o2.i1() + o3.i1() + o3.i2() + o4.i1() + o4.i2() + o5.c() + o6.c() + o6.i1() + o6.i2() + o7.c() + o7.i1() + o7.i2() + o8.g() + o9.g() + o9.i1() + o9.i2() + o10.g() + o10.i1() + o10.i2() +} + +class W { + private val o1 = object { fun foo() {} } + private val o2 = object : I1 {} + private val o3 = object : I1, I2 {} + private val o4 = object : I3 {} + private val o5 = object : C() {} + private val o6 = object : C(), I1, I2 {} + private val o7 = object : C(), I3 {} + private val o8 = object : G() {} + private val o9 = object : G(), I1, I2 {} + private val o10 = object : G(), I3 {} + + fun w() { + o1.foo() + o2.i1() + o3.i1() + o3.i2() + o4.i1() + o4.i2() + o5.c() + o6.c() + o6.i1() + o6.i2() + o7.c() + o7.i1() + o7.i2() + o8.g() + o9.g() + o9.i1() + o9.i2() + o10.g() + o10.i1() + o10.i2() + } +} + +object O { + private val o1 = object { fun foo() {} } + private val o2 = object : I1 {} + private val o3 = object : I1, I2 {} + private val o4 = object : I3 {} + private val o5 = object : C() {} + private val o6 = object : C(), I1, I2 {} + private val o7 = object : C(), I3 {} + private val o8 = object : G() {} + private val o9 = object : G(), I1, I2 {} + private val o10 = object : G(), I3 {} + + fun o() { + o1.foo() + o2.i1() + o3.i1() + o3.i2() + o4.i1() + o4.i2() + o5.c() + o6.c() + o6.i1() + o6.i2() + o7.c() + o7.i1() + o7.i2() + o8.g() + o9.g() + o9.i1() + o9.i2() + o10.g() + o10.i1() + o10.i2() + } +} diff --git a/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/output.txt b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/output.txt new file mode 100644 index 00000000000..174c604c79f --- /dev/null +++ b/compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/output.txt @@ -0,0 +1,10 @@ +compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/anonymousObjectTypeMetadata.kt:11:10: error: cannot access 'o3': it is private in file +val e1 = o3 + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/anonymousObjectTypeMetadata.kt:12:12: error: cannot access 'o7': it is private in 'W' +val e2 = w.o7 + ^ +compiler/testData/compileKotlinAgainstCustomBinaries/anonymousObjectTypeMetadata/anonymousObjectTypeMetadata.kt:13:12: error: cannot access 'o10': it is private in 'O' +val e3 = O.o10 + ^ +COMPILATION_ERROR diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt index da81812e3d5..b9cc2e1570e 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstCustomBinariesTest.kt @@ -725,6 +725,18 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration loadClassFile("SourceKt", tmpdir, library) } + fun testAnonymousObjectTypeMetadata() { + val library = compileCommonLibrary( + libraryName = "library", + ) + compileKotlin( + "anonymousObjectTypeMetadata.kt", + tmpdir, + listOf(library), + K2MetadataCompiler(), + ) + } + private fun loadClassFile(className: String, dir: File, library: File) { val classLoader = URLClassLoader(arrayOf(dir.toURI().toURL(), library.toURI().toURL())) val mainClass = classLoader.loadClass(className) diff --git a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/KlibMetadataStringTable.kt b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/KlibMetadataStringTable.kt index 4e95c9deba5..6c4b3005076 100644 --- a/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/KlibMetadataStringTable.kt +++ b/compiler/util-klib-metadata/src/org/jetbrains/kotlin/library/metadata/KlibMetadataStringTable.kt @@ -5,30 +5,6 @@ package org.jetbrains.kotlin.backend.common.serialization.metadata -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 -import org.jetbrains.kotlin.serialization.StringTableImpl +import org.jetbrains.kotlin.serialization.ApproximatingStringTable -class KlibMetadataStringTable : 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()) - } - } else { - super.getLocalClassIdReplacement(descriptor) - } - } -} +typealias KlibMetadataStringTable = ApproximatingStringTable diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/JavaScriptStringTable.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/JavaScriptStringTable.kt index 5137db0ea8a..3988e110008 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/JavaScriptStringTable.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/JavaScriptStringTable.kt @@ -16,30 +16,6 @@ package org.jetbrains.kotlin.serialization.js -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 -import org.jetbrains.kotlin.serialization.StringTableImpl +import org.jetbrains.kotlin.serialization.ApproximatingStringTable -class JavaScriptStringTable : 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()) - } - } else { - super.getLocalClassIdReplacement(descriptor) - } - } -} +typealias JavaScriptStringTable = ApproximatingStringTable