From ed2b9172da661dce46e09310ac71187bb0b0aff7 Mon Sep 17 00:00:00 2001 From: Mikhail Zarechenskiy Date: Thu, 13 Sep 2018 20:56:55 +0300 Subject: [PATCH] Support unsigned integers in `kotlinx-metadata-jvm` #KT-25371 Fixed --- libraries/kotlinx-metadata/jvm/ChangeLog.md | 4 ++ .../src/kotlinx/metadata/annotations.kt | 5 ++ .../src/kotlinx/metadata/impl/readUtils.kt | 16 ++++++- .../src/kotlinx/metadata/impl/writeUtils.kt | 21 +++++++++ libraries/tools/kotlinp/build.gradle.kts | 7 +++ .../org/jetbrains/kotlin/kotlinp/printers.kt | 5 ++ .../tools/kotlinp/testData/Annotations.kt | 16 +++++++ .../tools/kotlinp/testData/Annotations.txt | 47 +++++++++++++++++-- 8 files changed, 116 insertions(+), 5 deletions(-) diff --git a/libraries/kotlinx-metadata/jvm/ChangeLog.md b/libraries/kotlinx-metadata/jvm/ChangeLog.md index 0ff6f705010..fccdca1203a 100644 --- a/libraries/kotlinx-metadata/jvm/ChangeLog.md +++ b/libraries/kotlinx-metadata/jvm/ChangeLog.md @@ -1,5 +1,9 @@ # kotlinx-metadata-jvm +## 0.0.5 + +- [`KT-25371`](https://youtrack.jetbrains.com/issue/KT-25371) Support unsigned integers in kotlinx-metadata-jvm + ## 0.0.4 - [`KT-25920`](https://youtrack.jetbrains.com/issue/KT-25920) Compile kotlinx-metadata-jvm with JVM target bytecode version 1.6 instead of 1.8 diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/annotations.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/annotations.kt index 80b2f5788ff..3321ed5b0e3 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/annotations.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/annotations.kt @@ -37,6 +37,11 @@ sealed class KmAnnotationArgument { data class DoubleValue(override val value: Double) : KmAnnotationArgument() data class BooleanValue(override val value: Boolean) : KmAnnotationArgument() + data class UByteValue(override val value: Byte) : KmAnnotationArgument() + data class UShortValue(override val value: Short) : KmAnnotationArgument() + data class UIntValue(override val value: Int) : KmAnnotationArgument() + data class ULongValue(override val value: Long) : KmAnnotationArgument() + data class StringValue(override val value: String) : KmAnnotationArgument() data class KClassValue(override val value: ClassName) : KmAnnotationArgument() data class EnumValue(val enumClassName: ClassName, val enumEntryName: String) : KmAnnotationArgument() { diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/readUtils.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/readUtils.kt index 49e5bf7285a..f118bb8c04d 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/readUtils.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/readUtils.kt @@ -10,6 +10,7 @@ import kotlinx.metadata.KmAnnotation import kotlinx.metadata.KmAnnotationArgument import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf.Annotation.Argument.Value.Type.* +import org.jetbrains.kotlin.metadata.deserialization.Flags import org.jetbrains.kotlin.metadata.deserialization.NameResolver fun ProtoBuf.Annotation.readAnnotation(strings: NameResolver): KmAnnotation = @@ -22,8 +23,18 @@ fun ProtoBuf.Annotation.readAnnotation(strings: NameResolver): KmAnnotation = }.toMap() ) -private fun ProtoBuf.Annotation.Argument.Value.readAnnotationArgument(strings: NameResolver): KmAnnotationArgument<*>? = - when (type) { +private fun ProtoBuf.Annotation.Argument.Value.readAnnotationArgument(strings: NameResolver): KmAnnotationArgument<*>? { + if (Flags.IS_UNSIGNED[flags]) { + return when (type) { + BYTE -> KmAnnotationArgument.UByteValue(intValue.toByte()) + SHORT -> KmAnnotationArgument.UShortValue(intValue.toShort()) + INT -> KmAnnotationArgument.UIntValue(intValue.toInt()) + LONG -> KmAnnotationArgument.ULongValue(intValue) + else -> error("Cannot read value of unsigned type: $type") + } + } + + return when (type) { BYTE -> KmAnnotationArgument.ByteValue(intValue.toByte()) CHAR -> KmAnnotationArgument.CharValue(intValue.toChar()) SHORT -> KmAnnotationArgument.ShortValue(intValue.toShort()) @@ -39,6 +50,7 @@ private fun ProtoBuf.Annotation.Argument.Value.readAnnotationArgument(strings: N ARRAY -> KmAnnotationArgument.ArrayValue(arrayElementList.mapNotNull { it.readAnnotationArgument(strings) }) null -> null } +} internal fun NameResolver.getClassName(index: Int): ClassName { val name = getQualifiedClassName(index) diff --git a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/writeUtils.kt b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/writeUtils.kt index 4b09481adbc..6c2d10c036f 100644 --- a/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/writeUtils.kt +++ b/libraries/kotlinx-metadata/src/kotlinx/metadata/impl/writeUtils.kt @@ -10,6 +10,7 @@ import kotlinx.metadata.KmAnnotation import kotlinx.metadata.KmAnnotationArgument import kotlinx.metadata.isLocal import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.deserialization.Flags import org.jetbrains.kotlin.metadata.serialization.StringTable fun KmAnnotation.writeAnnotation(strings: StringTable): ProtoBuf.Annotation.Builder = @@ -58,6 +59,26 @@ private fun KmAnnotationArgument<*>.writeAnnotationArgument(strings: StringTable this.type = ProtoBuf.Annotation.Argument.Value.Type.BOOLEAN this.intValue = if (value) 1 else 0 } + is KmAnnotationArgument.UByteValue -> { + this.type = ProtoBuf.Annotation.Argument.Value.Type.BYTE + this.intValue = value.toLong() + this.flags = Flags.IS_UNSIGNED.toFlags(true) + } + is KmAnnotationArgument.UShortValue -> { + this.type = ProtoBuf.Annotation.Argument.Value.Type.SHORT + this.intValue = value.toLong() + this.flags = Flags.IS_UNSIGNED.toFlags(true) + } + is KmAnnotationArgument.UIntValue -> { + this.type = ProtoBuf.Annotation.Argument.Value.Type.INT + this.intValue = value.toLong() + this.flags = Flags.IS_UNSIGNED.toFlags(true) + } + is KmAnnotationArgument.ULongValue -> { + this.type = ProtoBuf.Annotation.Argument.Value.Type.LONG + this.intValue = value.toLong() + this.flags = Flags.IS_UNSIGNED.toFlags(true) + } is KmAnnotationArgument.StringValue -> { this.type = ProtoBuf.Annotation.Argument.Value.Type.STRING this.stringValue = strings.getStringIndex(value) diff --git a/libraries/tools/kotlinp/build.gradle.kts b/libraries/tools/kotlinp/build.gradle.kts index 3c327ce6176..9eb8afac802 100644 --- a/libraries/tools/kotlinp/build.gradle.kts +++ b/libraries/tools/kotlinp/build.gradle.kts @@ -1,4 +1,5 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile description = "kotlinp" @@ -55,3 +56,9 @@ tasks { dependsOn(":kotlin-script-runtime:dist") } } + +tasks.withType { + kotlinOptions { + freeCompilerArgs += listOf("-Xuse-experimental=kotlin.Experimental") + } +} \ No newline at end of file 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 e6fff58591b..9fbdca189e5 100644 --- a/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt +++ b/libraries/tools/kotlinp/src/org/jetbrains/kotlin/kotlinp/printers.kt @@ -427,6 +427,7 @@ private fun renderAnnotation(annotation: KmAnnotation): String = "$name = ${renderAnnotationArgument(argument)}" } +@UseExperimental(ExperimentalUnsignedTypes::class) private fun renderAnnotationArgument(arg: KmAnnotationArgument<*>): String = when (arg) { is KmAnnotationArgument.ByteValue -> arg.value.toString() + ".toByte()" @@ -436,6 +437,10 @@ private fun renderAnnotationArgument(arg: KmAnnotationArgument<*>): String = is KmAnnotationArgument.LongValue -> arg.value.toString() + "L" is KmAnnotationArgument.FloatValue -> arg.value.toString() + "f" is KmAnnotationArgument.DoubleValue -> arg.value.toString() + is KmAnnotationArgument.UByteValue -> arg.value.toUByte().toString() + ".toUByte()" + is KmAnnotationArgument.UShortValue -> arg.value.toUShort().toString() + ".toUShort()" + is KmAnnotationArgument.UIntValue -> arg.value.toUInt().toString() + "u" + is KmAnnotationArgument.ULongValue -> arg.value.toULong().toString() + "uL" is KmAnnotationArgument.BooleanValue -> arg.value.toString() is KmAnnotationArgument.StringValue -> "\"${arg.value.sanitize(quote = '"')}\"" is KmAnnotationArgument.KClassValue -> "${arg.value}::class" diff --git a/libraries/tools/kotlinp/testData/Annotations.kt b/libraries/tools/kotlinp/testData/Annotations.kt index 535a4601201..799cf094fca 100644 --- a/libraries/tools/kotlinp/testData/Annotations.kt +++ b/libraries/tools/kotlinp/testData/Annotations.kt @@ -10,6 +10,14 @@ annotation class A( val f: Float, val j: Long, val d: Double, + val ui: UInt, + val ub: UByte, + val us: UShort, + val ul: ULong, + val ui_max: UInt, + val ub_max: UByte, + val us_max: UShort, + val ul_max: ULong, val za: BooleanArray, val ca: CharArray, val ba: ByteArray, @@ -39,6 +47,14 @@ class C { -2.72f, 239239239239239L, 3.14, + 1u, + 0xFFu, + 3u, + 4uL, + 0xFFFF_FFFFu, + UByte.MAX_VALUE, + 0xFF_FFu, + 18446744073709551615u, [true], ['\''], [1.toByte()], diff --git a/libraries/tools/kotlinp/testData/Annotations.txt b/libraries/tools/kotlinp/testData/Annotations.txt index fb8a4ebbb9b..9f33a5a6e4d 100644 --- a/libraries/tools/kotlinp/testData/Annotations.txt +++ b/libraries/tools/kotlinp/testData/Annotations.txt @@ -2,8 +2,9 @@ // ------------------------------------------ public final annotation class A : kotlin/Annotation { - // signature: (ZCBSIFJD[Z[C[B[S[I[F[J[DLjava/lang/String;Lkotlin/annotation/AnnotationTarget;Lkotlin/reflect/KClass;LB;)V - public /* primary */ constructor(z: kotlin/Boolean, c: kotlin/Char, b: kotlin/Byte, s: kotlin/Short, i: kotlin/Int, f: kotlin/Float, j: kotlin/Long, d: kotlin/Double, za: kotlin/BooleanArray, ca: kotlin/CharArray, ba: kotlin/ByteArray, sa: kotlin/ShortArray, ia: kotlin/IntArray, fa: kotlin/FloatArray, ja: kotlin/LongArray, da: kotlin/DoubleArray, str: kotlin/String, enum: kotlin/annotation/AnnotationTarget, klass: kotlin/reflect/KClass<*>, anno: B) + // requires language version 1.3.0 (level=ERROR) + // signature: (ZCBSIFJDLkotlin/UInt;Lkotlin/UByte;Lkotlin/UShort;Lkotlin/ULong;Lkotlin/UInt;Lkotlin/UByte;Lkotlin/UShort;Lkotlin/ULong;[Z[C[B[S[I[F[J[DLjava/lang/String;Lkotlin/annotation/AnnotationTarget;Lkotlin/reflect/KClass;LB;)V + public /* primary */ constructor(z: kotlin/Boolean, c: kotlin/Char, b: kotlin/Byte, s: kotlin/Short, i: kotlin/Int, f: kotlin/Float, j: kotlin/Long, d: kotlin/Double, ui: kotlin/UInt, ub: kotlin/UByte, us: kotlin/UShort, ul: kotlin/ULong, ui_max: kotlin/UInt, ub_max: kotlin/UByte, us_max: kotlin/UShort, ul_max: kotlin/ULong, za: kotlin/BooleanArray, ca: kotlin/CharArray, ba: kotlin/ByteArray, sa: kotlin/ShortArray, ia: kotlin/IntArray, fa: kotlin/FloatArray, ja: kotlin/LongArray, da: kotlin/DoubleArray, str: kotlin/String, enum: kotlin/annotation/AnnotationTarget, klass: kotlin/reflect/KClass<*>, anno: B) // getter: anno()LB; public final val anno: B @@ -77,6 +78,46 @@ public final annotation class A : kotlin/Annotation { public final val str: kotlin/String public final get + // requires language version 1.3.0 (level=ERROR) + // getter: ub()B + public final val ub: kotlin/UByte + public final get + + // requires language version 1.3.0 (level=ERROR) + // getter: ub_max()B + public final val ub_max: kotlin/UByte + public final get + + // requires language version 1.3.0 (level=ERROR) + // getter: ui()I + public final val ui: kotlin/UInt + public final get + + // requires language version 1.3.0 (level=ERROR) + // getter: ui_max()I + public final val ui_max: kotlin/UInt + public final get + + // requires language version 1.3.0 (level=ERROR) + // getter: ul()J + public final val ul: kotlin/ULong + public final get + + // requires language version 1.3.0 (level=ERROR) + // getter: ul_max()J + public final val ul_max: kotlin/ULong + public final get + + // requires language version 1.3.0 (level=ERROR) + // getter: us()S + public final val us: kotlin/UShort + public final get + + // requires language version 1.3.0 (level=ERROR) + // getter: us_max()S + public final val us_max: kotlin/UShort + public final get + // getter: z()Z public final val z: kotlin/Boolean public final get @@ -107,7 +148,7 @@ public final class C : kotlin/Any { public final fun parameterTypeAnnotation(p: @JvmNamed(value = "Q_Q") kotlin/Any): kotlin/Any // signature: returnTypeAnnotation()V - public final fun returnTypeAnnotation(): @A(z = true, c = 'x', b = 1.toByte(), s = 42.toShort(), i = 42424242, f = -2.72f, j = 239239239239239L, d = 3.14, za = [true], ca = ['\''], ba = [1.toByte()], sa = [42.toShort()], ia = [42424242], fa = [-2.72f], ja = [239239239239239L], da = [3.14], str = "aba\ncaba'\"\t\u0001\u0002ꙮ", enum = kotlin/annotation/AnnotationTarget.CLASS, klass = C::class, anno = B(value = "aba\ncaba'\"\t\u0001\u0002ꙮ")) kotlin/Unit + public final fun returnTypeAnnotation(): @A(z = true, c = 'x', b = 1.toByte(), s = 42.toShort(), i = 42424242, f = -2.72f, j = 239239239239239L, d = 3.14, ui = 1u, ub = 255.toUByte(), us = 3.toUShort(), ul = 4uL, ui_max = 4294967295u, ub_max = 255.toUByte(), us_max = 65535.toUShort(), ul_max = 18446744073709551615uL, za = [true], ca = ['\''], ba = [1.toByte()], sa = [42.toShort()], ia = [42424242], fa = [-2.72f], ja = [239239239239239L], da = [3.14], str = "aba\ncaba'\"\t\u0001\u0002ꙮ", enum = kotlin/annotation/AnnotationTarget.CLASS, klass = C::class, anno = B(value = "aba\ncaba'\"\t\u0001\u0002ꙮ")) kotlin/Unit } // JvmNamed.class // ------------------------------------------