diff --git a/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/protoTypeTableUtil.kt b/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/protoTypeTableUtil.kt index f94979cdbf2..a693fc81a0d 100644 --- a/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/protoTypeTableUtil.kt +++ b/core/metadata/src/org/jetbrains/kotlin/metadata/deserialization/protoTypeTableUtil.kt @@ -23,6 +23,12 @@ import org.jetbrains.kotlin.metadata.ProtoBuf fun ProtoBuf.Class.supertypes(typeTable: TypeTable): List = supertypeList.takeIf(Collection<*>::isNotEmpty) ?: supertypeIdList.map { typeTable[it] } +fun ProtoBuf.Class.inlineClassUnderlyingType(typeTable: TypeTable): ProtoBuf.Type? = when { + hasInlineClassUnderlyingType() -> inlineClassUnderlyingType + hasInlineClassUnderlyingTypeId() -> typeTable[inlineClassUnderlyingTypeId] + else -> null +} + fun ProtoBuf.Type.Argument.type(typeTable: TypeTable): ProtoBuf.Type? = when { hasType() -> type hasTypeId() -> typeTable[typeId] diff --git a/libraries/kotlinx-metadata/jvm/ChangeLog.md b/libraries/kotlinx-metadata/jvm/ChangeLog.md index b2e0c6dc769..611094dc9e6 100644 --- a/libraries/kotlinx-metadata/jvm/ChangeLog.md +++ b/libraries/kotlinx-metadata/jvm/ChangeLog.md @@ -17,6 +17,7 @@ - Breaking change: deprecate `KotlinClassHeader.bytecodeVersion` and `KotlinClassHeader`'s constructor that takes a bytecode version array. Related to ['KT-41758`](https://youtrack.jetbrains.com/issue/KT-41758). - [`KT-45594`](https://youtrack.jetbrains.com/issue/KT-45594) KClass annotation argument containing array of classes is not read/written correctly +- [`KT-45635`](https://youtrack.jetbrains.com/issue/KT-45635) Add underlying property name & type for inline classes ## 0.2.0 diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/readers.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/readers.kt index 5cc6fd560c7..d1276f7ea2d 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/readers.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/readers.kt @@ -93,6 +93,13 @@ fun ProtoBuf.Class.accept( v.visitSealedSubclass(c.className(sealedSubclassFqName)) } + if (hasInlineClassUnderlyingPropertyName()) { + v.visitInlineClassUnderlyingPropertyName(c[inlineClassUnderlyingPropertyName]) + } + loadInlineClassUnderlyingType(c)?.let { underlyingType -> + v.visitInlineClassUnderlyingType(underlyingType.flags)?.let { underlyingType.accept(it, c) } + } + for (versionRequirement in versionRequirementList) { v.visitVersionRequirement()?.let { acceptVersionRequirementVisitor(versionRequirement, it, c) } } @@ -104,6 +111,18 @@ fun ProtoBuf.Class.accept( v.visitEnd() } +private fun ProtoBuf.Class.loadInlineClassUnderlyingType(c: ReadContext): ProtoBuf.Type? { + val type = inlineClassUnderlyingType(c.types) + if (type != null) return type + + if (!hasInlineClassUnderlyingPropertyName()) return null + + // Kotlin compiler doesn't write underlying type to metadata in case it can be loaded from the underlying property. + return propertyList + .singleOrNull { it.receiverType(c.types) == null && c[it.name] == c[inlineClassUnderlyingPropertyName] } + ?.returnType(c.types) +} + fun ProtoBuf.Package.accept( v: KmPackageVisitor, strings: NameResolver, diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/writers.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/writers.kt index a7616e55a69..402d3d21dea 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/writers.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/writers.kt @@ -457,6 +457,13 @@ open class ClassWriter(stringTable: StringTable, contextExtensions: List = ArrayList(0) + /** + * Name of the underlying property, if this class is `inline`. + */ + var inlineClassUnderlyingPropertyName: String? = null + + /** + * Type of the underlying property, if this class is `inline`. + */ + var inlineClassUnderlyingType: KmType? = null + /** * Version requirements on this class. */ @@ -140,6 +150,13 @@ class KmClass : KmClassVisitor(), KmDeclarationContainer { sealedSubclasses.add(name) } + override fun visitInlineClassUnderlyingPropertyName(name: String) { + inlineClassUnderlyingPropertyName = name + } + + override fun visitInlineClassUnderlyingType(flags: Flags): KmTypeVisitor = + KmType(flags).also { inlineClassUnderlyingType = it } + override fun visitVersionRequirement(): KmVersionRequirementVisitor = KmVersionRequirement().addTo(versionRequirements) @@ -163,6 +180,8 @@ class KmClass : KmClassVisitor(), KmDeclarationContainer { nestedClasses.forEach(visitor::visitNestedClass) enumEntries.forEach(visitor::visitEnumEntry) sealedSubclasses.forEach(visitor::visitSealedSubclass) + inlineClassUnderlyingPropertyName?.let(visitor::visitInlineClassUnderlyingPropertyName) + inlineClassUnderlyingType?.let { visitor.visitInlineClassUnderlyingType(it.flags)?.let(it::accept) } versionRequirements.forEach { visitor.visitVersionRequirement()?.let(it::accept) } extensions.forEach { visitor.visitExtensions(it.type)?.let(it::accept) } visitor.visitEnd() diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/visitors.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/visitors.kt index 97a829dd1f2..2863b893a6f 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/visitors.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/visitors.kt @@ -132,6 +132,23 @@ abstract class KmClassVisitor @JvmOverloads constructor(delegate: KmClassVisitor delegate?.visitSealedSubclass(name) } + /** + * Visits the name of the underlying property, if this class is `inline`. + * + * @param name the name of the underlying property. + */ + open fun visitInlineClassUnderlyingPropertyName(name: String) { + delegate?.visitInlineClassUnderlyingPropertyName(name) + } + + /** + * Visits the type of the underlying property, if this class is `inline`. + * + * @param flags type flags, consisting of [Flag.Type] flags + */ + open fun visitInlineClassUnderlyingType(flags: Flags): KmTypeVisitor? = + delegate?.visitInlineClassUnderlyingType(flags) + /** * Visits the version requirement on this class. */ diff --git a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt index 15b3791cb0b..67c1296f62b 100644 --- a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt +++ b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt @@ -767,6 +767,17 @@ class ClassPrinter(private val settings: KotlinpSettings) : KmClassVisitor(), Ab sb.appendLine(" // sealed subclass: $name") } + override fun visitInlineClassUnderlyingPropertyName(name: String) { + sb.appendLine() + sb.appendLine(" // underlying property: $name") + } + + override fun visitInlineClassUnderlyingType(flags: Flags): KmTypeVisitor? = + printType(flags) { + sb.appendLine() + sb.appendLine(" // underlying type: $it") + } + override fun visitVersionRequirement(): KmVersionRequirementVisitor? = printVersionRequirement { versionRequirements.add(it) } diff --git a/libraries/tools/kotlinp/testData/ValueClass.txt b/libraries/tools/kotlinp/testData/ValueClass.txt index 5e89791c085..c8c7ba4663a 100644 --- a/libraries/tools/kotlinp/testData/ValueClass.txt +++ b/libraries/tools/kotlinp/testData/ValueClass.txt @@ -21,6 +21,10 @@ public final value class Z : kotlin/Any { public final val s: kotlin/String public final get + // underlying property: s + + // underlying type: kotlin/String + // module name: test-module } // META-INF/test-module.kotlin_module