From 111a138a2a3cecb51dd9ff1b44873cd9e0ab2820 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 25 Feb 2015 16:06:16 +0300 Subject: [PATCH] Serialize secondary constructors --- .../SecondaryConstructors.A.kt | 9 +++++++ .../SecondaryConstructors.B.kt | 25 +++++++++++++++++++ ...mpileKotlinAgainstKotlinTestGenerated.java | 6 +++++ core/serialization/src/descriptors.proto | 2 +- .../serialization/DescriptorSerializer.java | 5 +++- .../deserialization/MemberDeserializer.kt | 7 +++--- .../DeserializedClassDescriptor.kt | 18 ++++++++----- .../org/jetbrains/kotlin/utils/collections.kt | 2 ++ 8 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 compiler/testData/compileKotlinAgainstKotlin/SecondaryConstructors.A.kt create mode 100644 compiler/testData/compileKotlinAgainstKotlin/SecondaryConstructors.B.kt diff --git a/compiler/testData/compileKotlinAgainstKotlin/SecondaryConstructors.A.kt b/compiler/testData/compileKotlinAgainstKotlin/SecondaryConstructors.A.kt new file mode 100644 index 00000000000..ff02a4a3207 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstKotlin/SecondaryConstructors.A.kt @@ -0,0 +1,9 @@ +open class A { + val prop: String + constructor(x1: String, x2: String = "abc") { + prop = "$x1#$x2" + } + constructor(x1: Long) { + prop = "$x1" + } +} diff --git a/compiler/testData/compileKotlinAgainstKotlin/SecondaryConstructors.B.kt b/compiler/testData/compileKotlinAgainstKotlin/SecondaryConstructors.B.kt new file mode 100644 index 00000000000..b80d0404af8 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstKotlin/SecondaryConstructors.B.kt @@ -0,0 +1,25 @@ +import java.lang + +class B1() : A("123") { + constructor(x1: Int): this() {} +} + +class B2 : A { + constructor(x1: String): super(x1) {} + constructor(): this("empty") {} + constructor(x1: Int): super(x1.toLong()) {} +} + +fun main(args: Array) { + val b1 = B1() + if (b1.prop != "123#abc") throw AssertionError("fail1: ${b1.prop}") + val b2 = B1(456) + if (b2.prop != "123#abc") throw AssertionError("fail2: ${b2.prop}") + + val b3 = B2("cde") + if (b3.prop != "cde#abc") throw AssertionError("fail3: ${b3.prop}") + val b4 = B2() + if (b4.prop != "empty#abc") throw AssertionError("fail4: ${b4.prop}") + val b5 = B2(789) + if (b5.prop != "789") throw AssertionError("fail5: ${b5.prop}") +} diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java index 90773ac50f9..936c2c37f66 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java @@ -144,6 +144,12 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl doTest(fileName); } + @TestMetadata("SecondaryConstructors.A.kt") + public void testSecondaryConstructors() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileKotlinAgainstKotlin/SecondaryConstructors.A.kt"); + doTest(fileName); + } + @TestMetadata("Simple.A.kt") public void testSimple() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileKotlinAgainstKotlin/Simple.A.kt"); diff --git a/core/serialization/src/descriptors.proto b/core/serialization/src/descriptors.proto index fb008d2a52d..61b62c4c2fb 100644 --- a/core/serialization/src/descriptors.proto +++ b/core/serialization/src/descriptors.proto @@ -201,7 +201,7 @@ message Class { // This field is present if and only if the class has a primary constructor optional PrimaryConstructor primary_constructor = 13; - // todo: other constructors? + repeated Callable secondary_constructor = 14; extensions 100 to 199; } diff --git a/core/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.java b/core/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.java index 242589fdf54..7f80bcca941 100644 --- a/core/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.java +++ b/core/serialization/src/org/jetbrains/kotlin/serialization/DescriptorSerializer.java @@ -110,7 +110,10 @@ public class DescriptorSerializer { } } - // TODO: other constructors + for (ConstructorDescriptor constructorDescriptor : classDescriptor.getConstructors()) { + if (constructorDescriptor.isPrimary()) continue; + builder.addSecondaryConstructor(callableProto(constructorDescriptor)); + } for (DeclarationDescriptor descriptor : sort(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors())) { if (descriptor instanceof CallableMemberDescriptor) { diff --git a/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt b/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt index 56e5e709684..40e7744fd9f 100644 --- a/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt +++ b/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/MemberDeserializer.kt @@ -31,7 +31,6 @@ public class MemberDeserializer(private val c: DeserializationContext) { return when (callableKind) { FUN -> loadFunction(proto) VAL, VAR -> loadProperty(proto) - CONSTRUCTOR -> loadConstructor(proto) else -> throw IllegalArgumentException("Unsupported callable kind: $callableKind") } } @@ -143,11 +142,11 @@ public class MemberDeserializer(private val c: DeserializationContext) { return (c.containingDeclaration as? ClassDescriptor)?.getThisAsReceiverParameter() } - private fun loadConstructor(proto: Callable): CallableMemberDescriptor { + public fun loadConstructor(proto: Callable, isPrimary: Boolean): ConstructorDescriptor { val classDescriptor = c.containingDeclaration as ClassDescriptor val descriptor = ConstructorDescriptorImpl.create( - classDescriptor, getAnnotations(proto, proto.getFlags(), AnnotatedCallableKind.FUNCTION), // TODO: primary - true, SourceElement.NO_SOURCE + classDescriptor, getAnnotations(proto, proto.getFlags(), AnnotatedCallableKind.FUNCTION), + isPrimary, SourceElement.NO_SOURCE ) val local = c.childContext(descriptor, listOf()) descriptor.initialize( diff --git a/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt b/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt index ef1ca4cfff1..dde9a10a1bb 100644 --- a/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt +++ b/core/serialization/src/org/jetbrains/kotlin/serialization/deserialization/descriptors/DeserializedClassDescriptor.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.serialization.deserialization import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.utils.singletonOrEmptyList import java.util.* public class DeserializedClassDescriptor( @@ -62,6 +63,7 @@ public class DeserializedClassDescriptor( private val containingDeclaration = outerContext.containingDeclaration private val primaryConstructor = c.storageManager.createNullableLazyValue { computePrimaryConstructor() } + private val constructors = c.storageManager.createLazyValue { computeConstructors() } private val defaultObjectDescriptor = c.storageManager.createNullableLazyValue { computeDefaultObjectDescriptor() } private val annotations = @@ -102,16 +104,20 @@ public class DeserializedClassDescriptor( return descriptor } - return c.memberDeserializer.loadCallable(constructorProto.getData()) as ConstructorDescriptor + return c.memberDeserializer.loadConstructor(constructorProto.getData(), true) } override fun getUnsubstitutedPrimaryConstructor(): ConstructorDescriptor? = primaryConstructor() - override fun getConstructors(): Collection { - val constructor = getUnsubstitutedPrimaryConstructor() ?: return listOf() - // TODO: other constructors - return listOf(constructor) - } + private fun computeConstructors(): Collection = + computeSecondaryConstructors() + getUnsubstitutedPrimaryConstructor().singletonOrEmptyList() + + private fun computeSecondaryConstructors(): List = + classProto.getSecondaryConstructorList().map { + c.memberDeserializer.loadConstructor(it, false) + } + + override fun getConstructors() = constructors() private fun computeDefaultObjectDescriptor(): ClassDescriptor? { if (!classProto.hasDefaultObjectName()) return null diff --git a/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt b/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt index 6c2627a5603..66cd1d6fb7b 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt +++ b/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt @@ -103,3 +103,5 @@ public fun newHashSetWithExpectedSize(expectedSize: Int): HashSet { public fun Collection.toReadOnlyList(): List = if (isEmpty()) Collections.emptyList() else ArrayList(this) + +public fun T?.singletonOrEmptyList(): List = if (this != null) Collections.singletonList(this) else Collections.emptyList()