diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtensionBase.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtensionBase.kt index c9de3028e13..6c4b03aabd6 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtensionBase.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/SerializerExtensionBase.kt @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.resolve.constants.NullValue import org.jetbrains.kotlin.types.KotlinType open class KotlinSerializerExtensionBase(private val protocol: SerializerExtensionProtocol) : SerializerExtension() { - override final val stringTable = StringTableImpl() + override val stringTable = StringTableImpl() override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder) { for (annotation in descriptor.annotations) { diff --git a/compiler/serialization/src/org/jetbrains/kotlin/serialization/StringTableImpl.kt b/compiler/serialization/src/org/jetbrains/kotlin/serialization/StringTableImpl.kt index d6feddceded..864c4760384 100644 --- a/compiler/serialization/src/org/jetbrains/kotlin/serialization/StringTableImpl.kt +++ b/compiler/serialization/src/org/jetbrains/kotlin/serialization/StringTableImpl.kt @@ -26,7 +26,7 @@ import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.utils.Interner import java.io.OutputStream -class StringTableImpl : StringTable { +open class StringTableImpl : StringTable { private class FqNameProto(val fqName: QualifiedName.Builder) { override fun hashCode(): Int { var result = 13 @@ -72,7 +72,7 @@ class StringTableImpl : StringTable { is ClassDescriptor -> { builder.parentQualifiedName = getFqNameIndex(containingDeclaration) } - else -> throw IllegalStateException("Cannot get FQ name of local class: " + descriptor) + else -> return getFqNameIndexOfLocalAnonymousClass(descriptor) } builder.shortName = getStringIndex(descriptor.name.asString()) @@ -80,6 +80,10 @@ class StringTableImpl : StringTable { return qualifiedNames.intern(FqNameProto(builder)) } + open fun getFqNameIndexOfLocalAnonymousClass(descriptor: ClassifierDescriptorWithTypeParameters): Int { + throw IllegalStateException("Cannot get FQ name of local class: " + descriptor) + } + fun getPackageFqNameIndex(fqName: FqName): Int { var result = -1 for (segment in fqName.pathSegments()) { diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.kt b/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.kt new file mode 100644 index 00000000000..a39f6766b27 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.kt @@ -0,0 +1,51 @@ +// MODULE: lib +// FILE: lib.kt + +interface I { + fun foo(): String +} + +abstract class A { + abstract fun bar(): String +} + +abstract class G { + abstract fun baz(): T +} + +class C { + private val propA = object : A() { + override fun bar() = "propA.bar" + + fun x() = "OK" + } + + private val propI = object : I { + override fun foo() = "propI.foo" + + fun x() = "OK" + } + + private val propAI = object : A(), I { + override fun foo() = "propAI.foo" + + override fun bar() = "propAI.bar" + + fun x() = "OK" + } + + private val propG = object : G() { + override fun baz() = "propG.baz" + + fun x() = "OK" + } +} + +// MODULE: main(lib) +// FILE: main.kt +fun test() { + println(C().propA.x()) + println(C().propI.x()) + println(C().propAI.x()) + println(C().propG.x()) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.txt b/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.txt new file mode 100644 index 00000000000..05713b910b5 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.txt @@ -0,0 +1,42 @@ +// -- Module: -- +package + +public abstract class A { + public constructor A() + public abstract fun bar(): kotlin.String + 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 +} + +public final class C { + public constructor C() + private final val propA: C.propA. + private final val propAI: C.propAI. + private final val propG: C.propG. + private final val propI: C.propI. + 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 +} + +public abstract class G { + public constructor G() + public abstract fun baz(): T + 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 +} + +public interface I { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + + +// -- Module:
-- +package + +public fun test(): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java index 055cde41a52..16d19a588a9 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithJsStdLibGenerated.java @@ -36,6 +36,12 @@ public class DiagnosticsTestWithJsStdLibGenerated extends AbstractDiagnosticsTes KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithJsStdLib"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("localClassMetadata.kt") + public void testLocalClassMetadata() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/localClassMetadata.kt"); + doTest(fileName); + } + @TestMetadata("runtimeAnnotations.kt") public void testRuntimeAnnotations() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithJsStdLib/runtimeAnnotations.kt"); 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 new file mode 100644 index 00000000000..7bdaa92dc1e --- /dev/null +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/JavaScriptStringTable.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.serialization.js + +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers +import org.jetbrains.kotlin.resolve.descriptorUtil.module +import org.jetbrains.kotlin.serialization.StringTableImpl + +class JavaScriptStringTable : StringTableImpl() { + override fun getFqNameIndexOfLocalAnonymousClass(descriptor: ClassifierDescriptorWithTypeParameters): Int { + return if (descriptor.containingDeclaration is CallableMemberDescriptor) { + val superClassifiers = descriptor.getAllSuperClassifiers() + .mapNotNull { it as ClassifierDescriptorWithTypeParameters } + .filter { it != descriptor } + .toList() + if (superClassifiers.size == 1) { + getFqNameIndex(superClassifiers[0]) + } + else { + val superClass = superClassifiers.find { !DescriptorUtils.isInterface(it) } + getFqNameIndex(superClass ?: descriptor.module.builtIns.any) + } + } + else { + super.getFqNameIndexOfLocalAnonymousClass(descriptor) + } + } +} diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerExtension.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerExtension.kt index c669e175b21..912a8dda20a 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerExtension.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/KotlinJavascriptSerializerExtension.kt @@ -28,6 +28,8 @@ import org.jetbrains.kotlin.types.FlexibleType class KotlinJavascriptSerializerExtension(private val fileRegistry: KotlinFileRegistry) : KotlinSerializerExtensionBase(JsSerializerProtocol) { + override val stringTable = JavaScriptStringTable() + override fun serializeFlexibleType(flexibleType: FlexibleType, lowerProto: ProtoBuf.Type.Builder, upperProto: ProtoBuf.Type.Builder) { lowerProto.flexibleTypeCapabilitiesId = stringTable.getStringIndex(DynamicTypeDeserializer.id) } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index 4946472880f..412e2562a33 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -5240,6 +5240,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("js/js.translator/testData/box/multiModule"), Pattern.compile("^([^_](.+))\\.kt$"), TargetBackend.JS, true); } + @TestMetadata("localClassMetadata.kt") + public void testLocalClassMetadata() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/multiModule/localClassMetadata.kt"); + doTest(fileName); + } + @TestMetadata("moduleAndVariableNameClash.kt") public void testModuleAndVariableNameClash() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/multiModule/moduleAndVariableNameClash.kt"); diff --git a/js/js.translator/testData/box/multiModule/localClassMetadata.kt b/js/js.translator/testData/box/multiModule/localClassMetadata.kt new file mode 100644 index 00000000000..8b661c8bc33 --- /dev/null +++ b/js/js.translator/testData/box/multiModule/localClassMetadata.kt @@ -0,0 +1,45 @@ +// MODULE: lib +// FILE: lib.kt + +interface I { + fun foo(): String +} + +abstract class A { + abstract fun bar(): String +} + +abstract class G { + abstract fun baz(): T +} + +class C { + private val propA = object : A() { + override fun bar() = "propA.bar" + } + + private val propI = object : I { + override fun foo() = "propI.foo" + } + + private val propAI = object : A(), I { + override fun foo() = "propAI.foo" + + override fun bar() = "propAI.bar" + } + + private val propG = object : G() { + override fun baz() = "propG.baz" + } + + fun test() = "${propA.bar()};${propI.foo()};${propAI.foo()};${propAI.bar()};${propG.baz()}" +} + +// 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" + + return "OK" +} \ No newline at end of file