From 7d2bc5c0f6066d7158e5e4b1ab4f19966fdf585d Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Sun, 16 Sep 2018 22:06:21 +0300 Subject: [PATCH] Properly load top-level constant initializers from multifile classes Before Kotlin 1.3-M2 we didn't write `has_field` flag for constants inside multifile classes. Now we write and rely on this when trying to load constant initializers, which is totally fine for binaries that were compiled with the 1.3-M2 or newer version. Unfortunately, constant initializers will not be loaded for old binaries. One way is to avoid relying on this flag, but then we'll get other problems (e.g. 3345dc81fd629ea48d1f33c41fcd4e549ba2313a). Therefore, for binaries that were compiled with at least 1.3-M2 version, we'll rely on the flag, otherwise, we won't. --- ...tBinaryClassAnnotationAndConstantLoader.kt | 22 +++++++++++++------ .../kotlin/DeserializedDescriptorResolver.kt | 2 ++ .../jvm/deserialization/JvmProtoBufUtil.kt | 10 +++++---- .../metadata/deserialization/BinaryVersion.kt | 3 +++ 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader.kt index c105c8c27c3..d7ea58185db 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/AbstractBinaryClassAnnotationAndConstantLoader.kt @@ -221,9 +221,6 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader( } override fun loadPropertyConstant(container: ProtoContainer, proto: ProtoBuf.Property, expectedType: KotlinType): C? { - val signature = getCallableSignature(proto, container.nameResolver, container.typeTable, AnnotatedCallableKind.PROPERTY) - ?: return null - val specialCase = getSpecialCaseContainerClass( container, property = true, @@ -233,6 +230,14 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader( ) val kotlinClass = findClassWithAnnotationsAndInitializers(container, specialCase) ?: return null + val requireHasFieldFlag = kotlinClass.classHeader.metadataVersion.isAtLeast( + DeserializedDescriptorResolver.KOTLIN_1_3_RC_METADATA_VERSION + ) + val signature = + getCallableSignature( + proto, container.nameResolver, container.typeTable, AnnotatedCallableKind.PROPERTY, requireHasFieldFlag + ) ?: return null + val constant = storage(kotlinClass).propertyConstants[signature] ?: return null return if (UnsignedTypes.isUnsignedType(expectedType)) transformToUnsignedConstant(constant) else constant } @@ -352,12 +357,14 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader( nameResolver: NameResolver, typeTable: TypeTable, field: Boolean = false, - synthetic: Boolean = false + synthetic: Boolean = false, + requireHasFieldFlagForField: Boolean = true ): MemberSignature? { val signature = proto.getExtensionOrNull(propertySignature) ?: return null if (field) { - val fieldSignature = JvmProtoBufUtil.getJvmFieldSignature(proto, nameResolver, typeTable) ?: return null + val fieldSignature = + JvmProtoBufUtil.getJvmFieldSignature(proto, nameResolver, typeTable, requireHasFieldFlagForField) ?: return null return MemberSignature.fromJvmMemberSignature(fieldSignature) } else if (synthetic && signature.hasSyntheticMethod()) { @@ -371,7 +378,8 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader( proto: MessageLite, nameResolver: NameResolver, typeTable: TypeTable, - kind: AnnotatedCallableKind + kind: AnnotatedCallableKind, + requireHasFieldFlagForField: Boolean = false ): MemberSignature? { return when { proto is ProtoBuf.Constructor -> { @@ -388,7 +396,7 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader( AnnotatedCallableKind.PROPERTY_SETTER -> if (signature.hasSetter()) MemberSignature.fromMethod(nameResolver, signature.setter) else null AnnotatedCallableKind.PROPERTY -> - getPropertySignature(proto, nameResolver, typeTable, true, true) + getPropertySignature(proto, nameResolver, typeTable, true, true, requireHasFieldFlagForField) else -> null } } diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.kt index c4631194392..8cdf3cad562 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/DeserializedDescriptorResolver.kt @@ -127,5 +127,7 @@ class DeserializedDescriptorResolver { private val KOTLIN_1_1_EAP_METADATA_VERSION = JvmMetadataVersion(1, 1, 2) private val KOTLIN_1_3_M1_METADATA_VERSION = JvmMetadataVersion(1, 1, 11) + + internal val KOTLIN_1_3_RC_METADATA_VERSION = JvmMetadataVersion(1, 1, 13) } } diff --git a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmProtoBufUtil.kt b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmProtoBufUtil.kt index 03753054cbc..148acfc05db 100644 --- a/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmProtoBufUtil.kt +++ b/core/metadata.jvm/src/org/jetbrains/kotlin/metadata/jvm/deserialization/JvmProtoBufUtil.kt @@ -104,14 +104,16 @@ object JvmProtoBufUtil { fun getJvmFieldSignature( proto: ProtoBuf.Property, nameResolver: NameResolver, - typeTable: TypeTable + typeTable: TypeTable, + requireHasFieldFlag: Boolean = true ): JvmMemberSignature.Field? { val signature = proto.getExtensionOrNull(JvmProtoBuf.propertySignature) ?: return null - val field = if (signature.hasField()) signature.field else return null + val field = if (signature.hasField()) signature.field else null + if (field == null && requireHasFieldFlag) return null - val name = if (field.hasName()) field.name else proto.name + val name = if (field != null && field.hasName()) field.name else proto.name val desc = - if (field.hasDesc()) nameResolver.getString(field.desc) + if (field != null && field.hasDesc()) nameResolver.getString(field.desc) else mapTypeDefault(proto.returnType(typeTable), nameResolver) ?: return null return JvmMemberSignature.Field(nameResolver.getString(name), desc) diff --git a/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/BinaryVersion.kt b/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/BinaryVersion.kt index d6ab3041893..84b512a1980 100644 --- a/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/BinaryVersion.kt +++ b/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/BinaryVersion.kt @@ -35,6 +35,9 @@ abstract class BinaryVersion(private vararg val numbers: Int) { else major == ourVersion.major && minor <= ourVersion.minor } + fun isAtLeast(version: BinaryVersion): Boolean = + isAtLeast(version.major, version.minor, version.patch) + fun isAtLeast(major: Int, minor: Int, patch: Int): Boolean { if (this.major > major) return true if (this.major < major) return false