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. 3345dc81fd).

 Therefore, for binaries that were compiled with at least 1.3-M2 version,
 we'll rely on the flag, otherwise, we won't.
This commit is contained in:
Mikhail Zarechenskiy
2018-09-16 22:06:21 +03:00
parent 8e66dadb47
commit 7d2bc5c0f6
4 changed files with 26 additions and 11 deletions
@@ -221,9 +221,6 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any>(
}
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<A : Any, C : Any>(
)
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<A : Any, C : Any>(
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<A : Any, C : Any>(
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<A : Any, C : Any>(
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
}
}
@@ -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)
}
}
@@ -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)
@@ -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