From 9933423a0bf7dfa3747a84492e201b54bcc88918 Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Tue, 12 Dec 2023 08:47:41 +0000 Subject: [PATCH] Add KmVersionRequirementKind.UNKNOWN for cases when the version requirement cannot be read correctly (missing from the table). It usually happens when we read the inner class' old metadata, which stored everything in the outer class' table. Fixes #KT-60870 Merge-request: KT-MR-13337 Merged-by: Leonid Startsev --- .../jvm/api/kotlinx-metadata-jvm.api | 2 + .../metadata/jvm/internal/JvmReadUtils.kt | 27 ++++--- .../test/UnknownVersionRequirementTest.kt | 73 +++++++++++++++++++ .../jvm/test/kotlinx/metadata/test/Utils.kt | 5 +- .../src/kotlinx/metadata/Nodes.kt | 4 + .../src/kotlinx/metadata/Visitors.kt | 16 ++++ .../src/kotlinx/metadata/internal/Readers.kt | 31 +++++--- .../src/kotlinx/metadata/internal/Writers.kt | 13 ++-- .../org/jetbrains/kotlin/kotlinp/printers.kt | 1 + 9 files changed, 141 insertions(+), 31 deletions(-) create mode 100644 libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/UnknownVersionRequirementTest.kt diff --git a/libraries/kotlinx-metadata/jvm/api/kotlinx-metadata-jvm.api b/libraries/kotlinx-metadata/jvm/api/kotlinx-metadata-jvm.api index 55e112d997e..2c66d88cc8b 100644 --- a/libraries/kotlinx-metadata/jvm/api/kotlinx-metadata-jvm.api +++ b/libraries/kotlinx-metadata/jvm/api/kotlinx-metadata-jvm.api @@ -1106,6 +1106,7 @@ public final class kotlinx/metadata/KmVersionRequirement : kotlinx/metadata/KmVe public final fun setLevel (Lkotlinx/metadata/KmVersionRequirementLevel;)V public final fun setMessage (Ljava/lang/String;)V public final fun setVersion (Lkotlinx/metadata/KmVersion;)V + public fun toString ()Ljava/lang/String; public fun visit (Lkotlinx/metadata/KmVersionRequirementVersionKind;Lkotlinx/metadata/KmVersionRequirementLevel;Ljava/lang/Integer;Ljava/lang/String;)V public fun visitVersion (III)V } @@ -1123,6 +1124,7 @@ public final class kotlinx/metadata/KmVersionRequirementVersionKind : java/lang/ public static final field API_VERSION Lkotlinx/metadata/KmVersionRequirementVersionKind; public static final field COMPILER_VERSION Lkotlinx/metadata/KmVersionRequirementVersionKind; public static final field LANGUAGE_VERSION Lkotlinx/metadata/KmVersionRequirementVersionKind; + public static final field UNKNOWN Lkotlinx/metadata/KmVersionRequirementVersionKind; public static fun getEntries ()Lkotlin/enums/EnumEntries; public static fun valueOf (Ljava/lang/String;)Lkotlinx/metadata/KmVersionRequirementVersionKind; public static fun values ()[Lkotlinx/metadata/KmVersionRequirementVersionKind; diff --git a/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/internal/JvmReadUtils.kt b/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/internal/JvmReadUtils.kt index 7ee4d05f33d..c50d72318d0 100644 --- a/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/internal/JvmReadUtils.kt +++ b/libraries/kotlinx-metadata/jvm/src/kotlinx/metadata/jvm/internal/JvmReadUtils.kt @@ -12,23 +12,26 @@ import kotlinx.metadata.KmPackage import kotlinx.metadata.internal.toKmClass import kotlinx.metadata.internal.toKmLambda import kotlinx.metadata.internal.toKmPackage -import kotlinx.metadata.jvm.KmModule -import kotlinx.metadata.jvm.KmPackageParts -import kotlinx.metadata.jvm.KotlinClassMetadata -import kotlinx.metadata.jvm.UnstableMetadataApi -import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion +import kotlinx.metadata.jvm.* +import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion as CompilerMetadataVersion import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping internal object JvmReadUtils { + + + private fun isLessThan14(annotationData: Metadata): Boolean { + return JvmMetadataVersion(annotationData.metadataVersion) < JvmMetadataVersion(1, 4, 0) + } + internal fun readKmClass(annotationData: Metadata): KmClass { val (strings, proto) = JvmProtoBufUtil.readClassDataFrom(annotationData.requireNotEmpty(), annotationData.data2) - return proto.toKmClass(strings) + return proto.toKmClass(strings, isLessThan14(annotationData)) } internal fun readKmPackage(annotationData: Metadata): KmPackage { val (strings, proto) = JvmProtoBufUtil.readPackageDataFrom(annotationData.requireNotEmpty(), annotationData.data2) - return proto.toKmPackage(strings) + return proto.toKmPackage(strings, isLessThan14(annotationData)) } internal fun readKmLambda(annotationData: Metadata): KmLambda? { @@ -37,7 +40,7 @@ internal object JvmReadUtils { JvmProtoBufUtil.readFunctionDataFrom(data1, annotationData.data2) } ?: return null val (strings, proto) = functionData - return proto.toKmLambda(strings) + return proto.toKmLambda(strings, isLessThan14(annotationData)) } internal fun readMetadataImpl(annotationData: Metadata, lenient: Boolean): KotlinClassMetadata { @@ -72,7 +75,7 @@ internal object JvmReadUtils { } for (classProto in data.moduleData.optionalAnnotations) { - v.optionalAnnotationClasses.add(classProto.toKmClass(data.moduleData.nameResolver)) + v.optionalAnnotationClasses.add(classProto.toKmClass(data.moduleData.nameResolver, false)) } return v } @@ -80,21 +83,21 @@ internal object JvmReadUtils { private fun checkMetadataVersionForRead(annotationData: Metadata, lenient: Boolean) { if (annotationData.metadataVersion.isEmpty()) throw IllegalArgumentException("Provided Metadata instance does not have metadataVersion in it and therefore is malformed and cannot be read.") - val jvmMetadataVersion = JvmMetadataVersion( + val jvmMetadataVersion = CompilerMetadataVersion( annotationData.metadataVersion, (annotationData.extraInt and (1 shl 3)/* see JvmAnnotationNames.METADATA_STRICT_VERSION_SEMANTICS_FLAG */) != 0 ) throwIfNotCompatible(jvmMetadataVersion, lenient) } - internal fun throwIfNotCompatible(jvmMetadataVersion: JvmMetadataVersion, lenient: Boolean) { + internal fun throwIfNotCompatible(jvmMetadataVersion: CompilerMetadataVersion, lenient: Boolean) { val isAtLeast110 = jvmMetadataVersion.isAtLeast(1, 1, 0) val isCompatible = if (lenient) isAtLeast110 else jvmMetadataVersion.isCompatibleWithCurrentCompilerVersion() if (!isCompatible) { // Kotlin 1.0 produces classfiles with metadataVersion = 1.1.0, while 1.0.0 represents unsupported pre-1.0 Kotlin (see JvmMetadataVersion.kt:39) val postfix = if (!isAtLeast110) "while minimum supported version is 1.1.0 (Kotlin 1.0)." - else "while maximum supported version is ${if (jvmMetadataVersion.isStrictSemantics) JvmMetadataVersion.INSTANCE else JvmMetadataVersion.INSTANCE_NEXT}. To support newer versions, update the kotlinx-metadata-jvm library." + else "while maximum supported version is ${if (jvmMetadataVersion.isStrictSemantics) CompilerMetadataVersion.INSTANCE else CompilerMetadataVersion.INSTANCE_NEXT}. To support newer versions, update the kotlinx-metadata-jvm library." throw IllegalArgumentException("Provided Metadata instance has version $jvmMetadataVersion, $postfix") } } diff --git a/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/UnknownVersionRequirementTest.kt b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/UnknownVersionRequirementTest.kt new file mode 100644 index 00000000000..7c968a322c7 --- /dev/null +++ b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/UnknownVersionRequirementTest.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package kotlinx.metadata.test + +import kotlinx.metadata.KmClass +import kotlinx.metadata.internal.ClassWriter +import kotlinx.metadata.jvm.JvmMetadataVersion +import kotlinx.metadata.jvm.KotlinClassMetadata +import kotlinx.metadata.jvm.Metadata +import kotlinx.metadata.jvm.internal.writeProtoBufData +import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable +import org.junit.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + +class UnknownVersionRequirementTest { + + @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") + @kotlin.internal.RequireKotlin("1.8.0", "foobar") + class Sample + + private val requireKotlinValue = "KmVersionRequirement(kind=LANGUAGE_VERSION, level=ERROR, version=1.8.0, errorCode=null, message=foobar)" + + private fun corrupt(original: KmClass): Pair, Array> { + val writer = ClassWriter(JvmStringTable()) + writer.writeClass(original) + writer.t.addVersionRequirement(239) // invalid + val (d1, d2) = writeProtoBufData(writer.t.build(), writer.c) + return d1 to d2 + } + + @Test + fun incorrectVersionRequirementFailsIfMetadataIsNew() { + val (d1, d2) = corrupt(Sample::class.java.readMetadataAsKmClass()) + val incorrect = + Metadata(KotlinClassMetadata.CLASS_KIND, JvmMetadataVersion.LATEST_STABLE_SUPPORTED.toIntArray(), d1, d2, extraInt = 0) + assertFailsWith { + incorrect.readMetadataAsClass() + } + } + + @Test + fun incorrectVersionRequirementHandledAsUnknown() { + val original = Sample::class.java.readMetadataAsKmClass() + assertEquals(1, original.versionRequirements.size) + assertEquals( + requireKotlinValue, + original.versionRequirements.single().toString() + ) + + val (d1, d2) = corrupt(original) + val incorrect = + Metadata(KotlinClassMetadata.CLASS_KIND, intArrayOf(1, 1, 3), d1, d2, extraInt = 0) + + val withInvalidRequirement = incorrect.readMetadataAsClass() + assertEquals(2, withInvalidRequirement.kmClass.versionRequirements.size) + assertEquals( + "[$requireKotlinValue, KmVersionRequirement(kind=UNKNOWN, level=HIDDEN, version=256.256.256, errorCode=null, message=null)]", + withInvalidRequirement.kmClass.versionRequirements.toString() + ) + + withInvalidRequirement.version = JvmMetadataVersion.LATEST_STABLE_SUPPORTED + val rewritten = withInvalidRequirement.write().readAsKmClass() + assertEquals(1, rewritten.versionRequirements.size) + assertEquals( + requireKotlinValue, + rewritten.versionRequirements.single().toString() + ) + } +} diff --git a/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/Utils.kt b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/Utils.kt index d304c71e969..f46ed2e371f 100644 --- a/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/Utils.kt +++ b/libraries/kotlinx-metadata/jvm/test/kotlinx/metadata/test/Utils.kt @@ -18,4 +18,7 @@ internal fun Metadata.readAsKmClass(): KmClass { } internal fun Class<*>.readMetadataAsKmClass(): KmClass = getMetadata().readAsKmClass() -internal fun Class<*>.readMetadataAsClass(): KotlinClassMetadata.Class = KotlinClassMetadata.readStrict(getMetadata()) as KotlinClassMetadata.Class + +internal fun Class<*>.readMetadataAsClass(): KotlinClassMetadata.Class = getMetadata().readMetadataAsClass() + +internal fun Metadata.readMetadataAsClass(): KotlinClassMetadata.Class = KotlinClassMetadata.readStrict(this) as KotlinClassMetadata.Class diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/Nodes.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/Nodes.kt index 6b2ebb53bfb..d467c5def91 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/Nodes.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/Nodes.kt @@ -1034,6 +1034,10 @@ public class KmVersionRequirement : KmVersionRequirementVisitor() { visitor.visitVersion(version.major, version.minor, version.patch) visitor.visitEnd() } + + override fun toString(): String { + return "KmVersionRequirement(kind=$kind, level=$level, version=$version, errorCode=$errorCode, message=$message)" + } } /** diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/Visitors.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/Visitors.kt index ef67af299df..2dc09bdb012 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/Visitors.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/Visitors.kt @@ -983,4 +983,20 @@ public enum class KmVersionRequirementVersionKind { * Indicates that certain API version is required. */ API_VERSION, + + /** + * Represents a version requirement not successfully parsed from the metadata. + * + * The old metadata format (from Kotlin 1.3 and earlier) did not have enough information for correct parsing of version requirements in some cases, + * so a stub of this kind is inserted instead. + * + * [KmVersionRequirement] with this kind always has [KmVersionRequirementLevel.HIDDEN] level, `256.256.256` [KmVersionRequirement.version], + * and `null` [KmVersionRequirement.errorCode] and [KmVersionRequirement.message]. + * + * Version requirements of this kind are being ignored by writers (i.e., are not written back). + * + * See the following issues for details: [KT-60870](https://youtrack.jetbrains.com/issue/KT-60870), [KT-25120](https://youtrack.jetbrains.com/issue/KT-25120) + */ + UNKNOWN + ; } diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/internal/Readers.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/internal/Readers.kt index 7d0ff695edd..080c1a00bf3 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/internal/Readers.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/internal/Readers.kt @@ -24,6 +24,7 @@ public class ReadContext( public val strings: NameResolver, public val types: TypeTable, @get:IgnoreInApiDump internal val versionRequirements: VersionRequirementTable, + internal val ignoreUnknownVersionRequirements: Boolean, private val parent: ReadContext? = null, internal val contextExtensions: List = emptyList() ) { @@ -41,7 +42,7 @@ public class ReadContext( typeParameterNameToId[name] ?: parent?.getTypeParameterId(name) internal fun withTypeParameters(typeParameters: List): ReadContext = - ReadContext(strings, types, versionRequirements, this, contextExtensions).apply { + ReadContext(strings, types, versionRequirements, ignoreUnknownVersionRequirements, this, contextExtensions).apply { for (typeParameter in typeParameters) { typeParameterNameToId[typeParameter.name] = typeParameter.id } @@ -51,6 +52,7 @@ public class ReadContext( @OptIn(ExperimentalContextReceivers::class) public fun ProtoBuf.Class.toKmClass( strings: NameResolver, + ignoreUnknownVersionRequirements: Boolean = false, contextExtensions: List = emptyList(), ): KmClass { val v = KmClass() @@ -58,6 +60,7 @@ public fun ProtoBuf.Class.toKmClass( strings, TypeTable(typeTable), VersionRequirementTable.create(versionRequirementTable), + ignoreUnknownVersionRequirements, contextExtensions = contextExtensions ).withTypeParameters(typeParameterList) @@ -105,6 +108,7 @@ private fun ProtoBuf.Class.loadInlineClassUnderlyingType(c: ReadContext): ProtoB public fun ProtoBuf.Package.toKmPackage( strings: NameResolver, + ignoreUnknownVersionRequirements: Boolean = false, contextExtensions: List = emptyList(), ): KmPackage { val v = KmPackage() @@ -112,6 +116,7 @@ public fun ProtoBuf.Package.toKmPackage( strings, TypeTable(typeTable), VersionRequirementTable.create(versionRequirementTable), + ignoreUnknownVersionRequirements, contextExtensions = contextExtensions ) @@ -131,11 +136,12 @@ public fun ProtoBuf.PackageFragment.toKmModuleFragment( strings, TypeTable(ProtoBuf.TypeTable.newBuilder().build()), VersionRequirementTable.EMPTY, + false, // toKmModuleFragment is used for klib only contextExtensions = contextExtensions ) - v.pkg = `package`.toKmPackage(strings, contextExtensions) - class_List.mapTo(v.classes) { it.toKmClass(strings, contextExtensions) } + v.pkg = `package`.toKmPackage(strings, false, contextExtensions) + class_List.mapTo(v.classes) { it.toKmClass(strings, false, contextExtensions) } c.extensions.forEach { it.readModuleFragmentExtensions(v, this, c) } @@ -153,9 +159,9 @@ private fun KmDeclarationContainer.visitDeclarations( protoTypeAliases.mapTo(typeAliases) { it.toKmTypeAlias(c) } } -public fun ProtoBuf.Function.toKmLambda(strings: NameResolver): KmLambda { +public fun ProtoBuf.Function.toKmLambda(strings: NameResolver, ignoreUnknownVersionRequirements: Boolean = false): KmLambda { val v = KmLambda() - val c = ReadContext(strings, TypeTable(typeTable), VersionRequirementTable.EMPTY) + val c = ReadContext(strings, TypeTable(typeTable), VersionRequirementTable.EMPTY, ignoreUnknownVersionRequirements) v.function = this.toKmFunction(c) return v } @@ -303,26 +309,27 @@ private fun ProtoBuf.Type.toKmType(c: ReadContext): KmType { private fun readVersionRequirement(id: Int, c: ReadContext): KmVersionRequirement { val v = KmVersionRequirement() val message = VersionRequirement.create(id, c.strings, c.versionRequirements) - ?: throw InconsistentKotlinMetadataException("No VersionRequirement with the given id in the table") + if (message == null && !c.ignoreUnknownVersionRequirements) throw InconsistentKotlinMetadataException("No VersionRequirement with the given id in the table") - val kind = when (message.kind) { + val kind = when (message?.kind) { ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION -> KmVersionRequirementVersionKind.LANGUAGE_VERSION ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION -> KmVersionRequirementVersionKind.COMPILER_VERSION ProtoBuf.VersionRequirement.VersionKind.API_VERSION -> KmVersionRequirementVersionKind.API_VERSION + null -> KmVersionRequirementVersionKind.UNKNOWN } - val level = when (message.level) { + val level = when (message?.level) { DeprecationLevel.WARNING -> KmVersionRequirementLevel.WARNING DeprecationLevel.ERROR -> KmVersionRequirementLevel.ERROR - DeprecationLevel.HIDDEN -> KmVersionRequirementLevel.HIDDEN + DeprecationLevel.HIDDEN, null -> KmVersionRequirementLevel.HIDDEN } v.kind = kind v.level = level - v.errorCode = message.errorCode - v.message = message.message + v.errorCode = message?.errorCode + v.message = message?.message - val (major, minor, patch) = message.version + val (major, minor, patch) = message?.version ?: VersionRequirement.Version.INFINITY v.version = KmVersion(major, minor, patch) return v } diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/internal/Writers.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/internal/Writers.kt index 5625d5f0a38..2e77cb4b018 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/internal/Writers.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/internal/Writers.kt @@ -110,7 +110,7 @@ private fun WriteContext.writeConstructor(kmConstructor: KmConstructor): ProtoBu kmConstructor.valueParameters.forEach { t.addValueParameter(writeValueParameter(it).build()) } - kmConstructor.versionRequirements.forEach { t.addVersionRequirement(writeVersionRequirement(it)) } + t.addAllVersionRequirement(kmConstructor.versionRequirements.mapNotNull(::writeVersionRequirement)) extensions.forEach { it.writeConstructorExtensions(kmConstructor, t, this) } @@ -129,7 +129,7 @@ private fun WriteContext.writeFunction(kmFunction: KmFunction): ProtoBuf.Functio t.addAllContextReceiverType(kmFunction.contextReceiverTypes.map { writeType(it).build() }) t.addAllValueParameter(kmFunction.valueParameters.map { writeValueParameter(it).build() }) t.returnType = writeType(kmFunction.returnType).build() - t.addAllVersionRequirement(kmFunction.versionRequirements.map(::writeVersionRequirement)) + t.addAllVersionRequirement(kmFunction.versionRequirements.mapNotNull(::writeVersionRequirement)) @OptIn(ExperimentalContracts::class) kmFunction.contract?.let { t.contract = writeContract(it) } @@ -156,7 +156,7 @@ public fun WriteContext.writeProperty(kmProperty: KmProperty): ProtoBuf.Property t.addAllContextReceiverType(kmProperty.contextReceiverTypes.map { writeType(it).build() }) kmProperty.setterParameter?.let { t.setterValueParameter = writeValueParameter(it).build() } t.returnType = writeType(kmProperty.returnType).build() - t.addAllVersionRequirement(kmProperty.versionRequirements.map { writeVersionRequirement(it) }) + t.addAllVersionRequirement(kmProperty.versionRequirements.mapNotNull { writeVersionRequirement(it) }) extensions.forEach { it.writePropertyExtensions(kmProperty, t, this) } @@ -192,7 +192,7 @@ private fun WriteContext.writeTypeAlias( t.underlyingType = writeType(typeAlias.underlyingType).build() t.expandedType = writeType(typeAlias.expandedType).build() t.addAllAnnotation(typeAlias.annotations.map { it.writeAnnotation(strings).build() }) - t.addAllVersionRequirement(typeAlias.versionRequirements.map(::writeVersionRequirement)) + t.addAllVersionRequirement(typeAlias.versionRequirements.mapNotNull(::writeVersionRequirement)) extensions.forEach { it.writeTypeAliasExtensions(typeAlias, t, this) } if (typeAlias.flags != ProtoBuf.TypeAlias.getDefaultInstance().flags) { @@ -202,7 +202,7 @@ private fun WriteContext.writeTypeAlias( return t } -private fun WriteContext.writeVersionRequirement(kmVersionRequirement: KmVersionRequirement): Int { +private fun WriteContext.writeVersionRequirement(kmVersionRequirement: KmVersionRequirement): Int? { val kind = kmVersionRequirement.kind val level = kmVersionRequirement.level val errorCode = kmVersionRequirement.errorCode @@ -212,6 +212,7 @@ private fun WriteContext.writeVersionRequirement(kmVersionRequirement: KmVersion KmVersionRequirementVersionKind.LANGUAGE_VERSION -> ProtoBuf.VersionRequirement.VersionKind.LANGUAGE_VERSION KmVersionRequirementVersionKind.COMPILER_VERSION -> ProtoBuf.VersionRequirement.VersionKind.COMPILER_VERSION KmVersionRequirementVersionKind.API_VERSION -> ProtoBuf.VersionRequirement.VersionKind.API_VERSION + KmVersionRequirementVersionKind.UNKNOWN -> return null } if (versionKind != defaultInstanceForType.versionKind) { this.versionKind = versionKind @@ -329,7 +330,7 @@ public open class ClassWriter(stringTable: StringTable, contextExtensions: List< @OptIn(ExperimentalContextReceivers::class) t.addAllContextReceiverType(kmClass.contextReceiverTypes.map { c.writeType(it).build() }) - t.addAllVersionRequirement(kmClass.versionRequirements.map { c.writeVersionRequirement(it) }) + t.addAllVersionRequirement(kmClass.versionRequirements.mapNotNull { c.writeVersionRequirement(it) }) c.extensions.forEach { it.writeClassExtensions(kmClass, t, c) } 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 49f1686cd0b..1a7c54bc143 100644 --- a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt +++ b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt @@ -322,6 +322,7 @@ private fun printVersionRequirement(versionRequirement: KmVersionRequirement): S KmVersionRequirementVersionKind.LANGUAGE_VERSION -> "language version" KmVersionRequirementVersionKind.COMPILER_VERSION -> "compiler version" KmVersionRequirementVersionKind.API_VERSION -> "API version" + KmVersionRequirementVersionKind.UNKNOWN -> "unknown requirement" } ).append(" ").append(version)