Move version requirements serialization for @JvmDefault to JvmSerializerExtension

This commit is contained in:
Mikhael Bogdanov
2018-06-26 14:46:44 +02:00
parent 0ca3afbb34
commit b412c90cef
6 changed files with 78 additions and 36 deletions
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.java.JavaClassProtoBuf
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.serialization.DescriptorSerializer
@@ -28,8 +29,12 @@ import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerial
// It uses BuiltInSerializerProtocol for annotations serialization
class JavaClassesSerializerExtension : KotlinSerializerExtensionBase(BuiltInSerializerProtocol) {
override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder) {
super.serializeClass(descriptor, proto)
override fun serializeClass(
descriptor: ClassDescriptor,
proto: ProtoBuf.Class.Builder,
versionRequirementTable: MutableVersionRequirementTable
) {
super.serializeClass(descriptor, proto, versionRequirementTable)
if (descriptor.visibility == JavaVisibilities.PACKAGE_VISIBILITY) {
proto.setExtension(JavaClassProtoBuf.isPackagePrivateClass, true)
}
@@ -19,12 +19,16 @@ import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.ClassMapperLite
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.protobuf.GeneratedMessageLite
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface
import org.jetbrains.kotlin.resolve.annotations.hasJvmDefaultAnnotation
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.nonSourceAnnotations
import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.serialization.DescriptorSerializer.Companion.writeVersionRequirement
import org.jetbrains.kotlin.serialization.SerializerExtension
import org.jetbrains.kotlin.types.FlexibleType
import org.jetbrains.kotlin.types.KotlinType
@@ -45,7 +49,11 @@ class JvmSerializerExtension(private val bindings: JvmSerializationBindings, sta
return useTypeTable
}
override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder) {
override fun serializeClass(
descriptor: ClassDescriptor,
proto: ProtoBuf.Class.Builder,
versionRequirementTable: MutableVersionRequirementTable
) {
if (moduleName != JvmAbi.DEFAULT_MODULE_NAME) {
proto.setExtension(JvmProtoBuf.classModuleName, stringTable.getStringIndex(moduleName))
}
@@ -53,6 +61,26 @@ class JvmSerializerExtension(private val bindings: JvmSerializationBindings, sta
val containerAsmType =
if (DescriptorUtils.isInterface(descriptor)) typeMapper.mapDefaultImpls(descriptor) else typeMapper.mapClass(descriptor)
writeLocalProperties(proto, containerAsmType, JvmProtoBuf.classLocalVariable)
writeVersionRequirementForJvmDefaultIfNeeded(descriptor, proto, versionRequirementTable)
}
// Interfaces which have @JvmDefault members somewhere in the hierarchy need the compiler 1.2.40+
// so that the generated bridges in subclasses would call the super members correctly
private fun writeVersionRequirementForJvmDefaultIfNeeded(
classDescriptor: ClassDescriptor,
builder: ProtoBuf.Class.Builder,
versionRequirementTable: MutableVersionRequirementTable
) {
if (
isInterface(classDescriptor) &&
classDescriptor.unsubstitutedMemberScope.getContributedDescriptors().any {
it is CallableMemberDescriptor && it.hasJvmDefaultAnnotation()
}
) {
assert(!builder.hasVersionRequirement()) { "VersionRequirement should be empty for $classDescriptor" }
builder.versionRequirement =
writeVersionRequirement(1, 2, 40, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION, versionRequirementTable)
}
}
override fun serializePackage(packageFqName: FqName, proto: ProtoBuf.Package.Builder) {
@@ -20,8 +20,7 @@ import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTabl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry
import org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface
import org.jetbrains.kotlin.resolve.DescriptorUtils.*
import org.jetbrains.kotlin.resolve.MemberComparator
import org.jetbrains.kotlin.resolve.RequireKotlinNames
import org.jetbrains.kotlin.resolve.annotations.hasJvmDefaultAnnotation
@@ -144,16 +143,14 @@ class DescriptorSerializer private constructor(
val requirement = serializeVersionRequirement(classDescriptor)
if (requirement != null) {
builder.versionRequirement = requirement
} else {
writeVersionRequirementForJvmDefaultIfNeeded(classDescriptor, builder)
}
extension.serializeClass(classDescriptor, builder, versionRequirementTable)
val versionRequirementTableProto = versionRequirementTable.serialize()
if (versionRequirementTableProto != null) {
builder.versionRequirementTable = versionRequirementTableProto
}
extension.serializeClass(classDescriptor, builder)
return builder
}
@@ -622,19 +619,6 @@ class DescriptorSerializer private constructor(
return builder
}
// Interfaces which have @JvmDefault members somewhere in the hierarchy need the compiler 1.2.40+
// so that the generated bridges in subclasses would call the super members correctly
private fun writeVersionRequirementForJvmDefaultIfNeeded(classDescriptor: ClassDescriptor, builder: ProtoBuf.Class.Builder) {
if (
isInterface(classDescriptor) &&
classDescriptor.unsubstitutedMemberScope.getContributedDescriptors().any {
it is CallableMemberDescriptor && it.hasJvmDefaultAnnotation()
}
) {
builder.versionRequirement = writeVersionRequirement(1, 2, 40, ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION)
}
}
private fun writeVersionRequirement(languageFeature: LanguageFeature): Int {
val languageVersion = languageFeature.sinceVersion!!
return writeVersionRequirement(
@@ -644,16 +628,7 @@ class DescriptorSerializer private constructor(
}
private fun writeVersionRequirement(major: Int, minor: Int, patch: Int, versionKind: ProtoBuf.VersionRequirement.VersionKind): Int {
val requirement = ProtoBuf.VersionRequirement.newBuilder().apply {
VersionRequirement.Version(major, minor, patch).encode(
writeVersion = { version = it },
writeVersionFull = { versionFull = it }
)
if (versionKind != defaultInstanceForType.versionKind) {
this.versionKind = versionKind
}
}
return versionRequirementTable[requirement]
return writeVersionRequirement(major, minor, patch, versionKind, versionRequirementTable)
}
// Returns index into versionRequirementTable, or null if there's no @RequireKotlin on the descriptor
@@ -782,5 +757,24 @@ class DescriptorSerializer private constructor(
//NOTE: the exact comparator does matter here
Collections.sort(this, MemberComparator.INSTANCE)
}
fun writeVersionRequirement(
major: Int,
minor: Int,
patch: Int,
versionKind: ProtoBuf.VersionRequirement.VersionKind,
versionRequirementTable: MutableVersionRequirementTable
): Int {
val requirement = ProtoBuf.VersionRequirement.newBuilder().apply {
VersionRequirement.Version(major, minor, patch).encode(
writeVersion = { version = it },
writeVersionFull = { versionFull = it }
)
if (versionKind != defaultInstanceForType.versionKind) {
this.versionKind = versionKind
}
}
return versionRequirementTable[requirement]
}
}
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.serialization
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.FlexibleType
import org.jetbrains.kotlin.types.KotlinType
@@ -27,7 +28,11 @@ abstract class SerializerExtension {
get() = null
open fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder) {
open fun serializeClass(
descriptor: ClassDescriptor,
proto: ProtoBuf.Class.Builder,
versionRequirementTable: MutableVersionRequirementTable
) {
}
open fun serializePackage(packageFqName: FqName, proto: ProtoBuf.Package.Builder) {
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.serialization
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.constants.NullValue
import org.jetbrains.kotlin.resolve.descriptorUtil.nonSourceAnnotations
@@ -26,7 +27,11 @@ import org.jetbrains.kotlin.types.KotlinType
open class KotlinSerializerExtensionBase(private val protocol: SerializerExtensionProtocol) : SerializerExtension() {
override val stringTable = StringTableImpl()
override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder) {
override fun serializeClass(
descriptor: ClassDescriptor,
proto: ProtoBuf.Class.Builder,
versionRequirementTable: MutableVersionRequirementTable
) {
for (annotation in descriptor.nonSourceAnnotations) {
proto.addExtension(protocol.classAnnotation, annotationSerializer.serializeAnnotation(annotation))
}
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.js.JsProtoBuf
import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
@@ -41,12 +42,16 @@ class KotlinJavascriptSerializerExtension(
lowerProto.flexibleTypeCapabilitiesId = stringTable.getStringIndex(DynamicTypeDeserializer.id)
}
override fun serializeClass(descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder) {
override fun serializeClass(
descriptor: ClassDescriptor,
proto: ProtoBuf.Class.Builder,
versionRequirementTable: MutableVersionRequirementTable
) {
val id = getFileId(descriptor)
if (id != null) {
proto.setExtension(JsProtoBuf.classContainingFileId, id)
}
super.serializeClass(descriptor, proto)
super.serializeClass(descriptor, proto, versionRequirementTable)
}
override fun serializeProperty(descriptor: PropertyDescriptor, proto: ProtoBuf.Property.Builder) {