JVM IR: generate correct metadata for multi-file classes

This commit is contained in:
Alexander Udalov
2019-07-23 13:54:43 +02:00
parent 4be0e00071
commit f01b0f6467
9 changed files with 55 additions and 27 deletions
@@ -307,27 +307,17 @@ class MultifileClassCodegenImpl(
val extraFlags = if (shouldGeneratePartHierarchy) JvmAnnotationNames.METADATA_MULTIFILE_PARTS_INHERIT_FLAG else 0
writeKotlinMetadata(classBuilder, state, KotlinClassHeader.Kind.MULTIFILE_CLASS, extraFlags) { av ->
val arv = av.visitArray(JvmAnnotationNames.METADATA_DATA_FIELD_NAME)
for (internalName in partInternalNamesSorted) {
arv.visit(null, internalName)
}
arv.visitEnd()
val kotlinPackageFqName =
packageFragment?.fqName ?: compiledPackageFragment?.fqName
?: error("Either source package or compiled package should not be null: $facadeClassType ($files)")
val kotlinPackageFqName =
packageFragment?.fqName ?: compiledPackageFragment?.fqName
?: error("Either source package or compiled package should not be null: $facadeClassType ($files)")
if (files.any { it.packageFqName != kotlinPackageFqName })
throw UnsupportedOperationException(
"Multi-file parts of a facade with JvmPackageName should all lie in the same Kotlin package:\n " +
files.joinToString("\n ") { file -> "$file: package ${file.packageFqName}" }
)
if (files.any { it.packageFqName != kotlinPackageFqName })
throw UnsupportedOperationException(
"Multi-file parts of a facade with JvmPackageName should all lie in the same Kotlin package:\n " +
files.joinToString("\n ") { file -> "$file: package ${file.packageFqName}" }
)
if (kotlinPackageFqName != JvmClassName.byInternalName(facadeClassType.internalName).packageFqName) {
av.visit(JvmAnnotationNames.METADATA_PACKAGE_NAME_FIELD_NAME, kotlinPackageFqName.asString())
}
}
writeMetadata(classBuilder, state, extraFlags, partInternalNamesSorted, facadeClassType, kotlinPackageFqName)
}
private fun createCodegenForDelegatesInMultifileFacade(facadeContext: FieldOwnerContext<*>): MemberCodegen<KtFile> =
@@ -375,5 +365,26 @@ class MultifileClassCodegenImpl(
return incrementalPackageFragment?.getPackageFragmentForMultifileClass(facadeFqName)
}
fun writeMetadata(
classBuilder: ClassBuilder,
state: GenerationState,
flags: Int,
partInternalNames: List<String>,
facadeClassType: Type,
kotlinPackageFqName: FqName
) {
writeKotlinMetadata(classBuilder, state, KotlinClassHeader.Kind.MULTIFILE_CLASS, flags) { av ->
val arv = av.visitArray(JvmAnnotationNames.METADATA_DATA_FIELD_NAME)
for (internalName in partInternalNames) {
arv.visit(null, internalName)
}
arv.visitEnd()
if (kotlinPackageFqName != JvmClassName.byInternalName(facadeClassType.internalName).packageFqName) {
av.visit(JvmAnnotationNames.METADATA_PACKAGE_NAME_FIELD_NAME, kotlinPackageFqName.asString())
}
}
}
}
}
@@ -65,6 +65,7 @@ class JvmBackendContext(
internal val localDelegatedProperties = mutableMapOf<IrClass, List<IrLocalDelegatedPropertySymbol>>()
internal val multifileFacadesToAdd = mutableMapOf<JvmClassName, MutableList<IrClass>>()
internal val multifileFacadeForPart = mutableMapOf<IrClass, JvmClassName>()
override var inVerbosePhase: Boolean = false
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
@@ -144,13 +145,31 @@ open class ClassCodegen protected constructor(
serializerExtension.serializeJvmPackage(packageProto, type)
writeKotlinMetadata(visitor, state, KotlinClassHeader.Kind.FILE_FACADE, 0) {
AsmUtil.writeAnnotationData(it, serializer, packageProto.build())
val facadeClassName = context.multifileFacadeForPart[irClass.attributeOwnerId]
val kind = if (facadeClassName != null) KotlinClassHeader.Kind.MULTIFILE_CLASS_PART else KotlinClassHeader.Kind.FILE_FACADE
writeKotlinMetadata(visitor, state, kind, 0) { av ->
AsmUtil.writeAnnotationData(av, serializer, packageProto.build())
if (facadeClassName != null) {
av.visit(JvmAnnotationNames.METADATA_MULTIFILE_CLASS_NAME_FIELD_NAME, facadeClassName.internalName)
}
// TODO: JvmPackageName
}
}
else -> {
writeSyntheticClassMetadata(visitor, state)
val entry = irClass.fileParent.fileEntry
if (entry is MultifileFacadeFileEntry) {
val partInternalNames = entry.partFiles.mapNotNull { partFile ->
val fileClass = partFile.declarations.singleOrNull { it.origin == IrDeclarationOrigin.FILE_CLASS } as IrClass?
if (fileClass != null) typeMapper.mapClass(fileClass).internalName else null
}
MultifileClassCodegenImpl.writeMetadata(
visitor, state, 0 /* TODO */, partInternalNames, type, irClass.fqNameWhenAvailable!!.parent()
)
} else {
writeSyntheticClassMetadata(visitor, state)
}
}
}
}
@@ -85,6 +85,8 @@ private fun generateMultifileFacades(module: ModuleDescriptor, context: JvmBacke
file.declarations.add(facadeClass)
for (partClass in partClasses) {
context.multifileFacadeForPart[partClass.attributeOwnerId as IrClass] = jvmClassName
for (member in partClass.declarations) {
member.createMultifileDelegateIfNeeded(context, facadeClass)
}
@@ -1 +0,0 @@
// IGNORE_BACKEND: JVM_IR
@@ -1 +0,0 @@
// IGNORE_BACKEND: JVM_IR
@@ -1 +0,0 @@
// IGNORE_BACKEND: JVM_IR
@@ -1 +0,0 @@
// IGNORE_BACKEND: JVM_IR
@@ -1 +0,0 @@
// IGNORE_BACKEND: JVM_IR