Value classes: Allow unsigned arrays in annotations
including varargs, apparently. So, we allow unsigned types and unsigned arrays in annotations, but disallow user-defined inline classes. #KT-23816 Fixed
This commit is contained in:
Generated
+5
@@ -32129,6 +32129,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/equalsImplForInlineClassWrappingNullableInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("evaluateConstructorOfUnsignedArrayType.kt")
|
||||
public void testEvaluateConstructorOfUnsignedArrayType() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/evaluateConstructorOfUnsignedArrayType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("evaluateConstructorOfUnsignedType.kt")
|
||||
public void testEvaluateConstructorOfUnsignedType() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/evaluateConstructorOfUnsignedType.kt");
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.resolve
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.builtins.UnsignedTypes
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
@@ -93,12 +94,16 @@ class CollectionLiteralResolver(
|
||||
}
|
||||
|
||||
private fun getArrayFunctionCallName(expectedType: KotlinType): Name {
|
||||
if (NO_EXPECTED_TYPE === expectedType || !KotlinBuiltIns.isPrimitiveArray(expectedType)) {
|
||||
if (NO_EXPECTED_TYPE === expectedType ||
|
||||
!(KotlinBuiltIns.isPrimitiveArray(expectedType) || KotlinBuiltIns.isUnsignedArrayType(expectedType))
|
||||
) {
|
||||
return ArrayFqNames.ARRAY_OF_FUNCTION
|
||||
}
|
||||
|
||||
val descriptor = expectedType.constructor.declarationDescriptor ?: return ArrayFqNames.ARRAY_OF_FUNCTION
|
||||
|
||||
return ArrayFqNames.PRIMITIVE_TYPE_TO_ARRAY[KotlinBuiltIns.getPrimitiveArrayType(descriptor)] ?: ArrayFqNames.ARRAY_OF_FUNCTION
|
||||
return ArrayFqNames.PRIMITIVE_TYPE_TO_ARRAY[KotlinBuiltIns.getPrimitiveArrayType(descriptor)]
|
||||
?: UnsignedTypes.unsignedArrayTypeToArrayCall[UnsignedTypes.toUnsignedArrayType(descriptor)]
|
||||
?: ArrayFqNames.ARRAY_OF_FUNCTION
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,11 @@ public class CompileTimeConstantUtils {
|
||||
"kotlin.shortArrayOf",
|
||||
"kotlin.byteArrayOf",
|
||||
"kotlin.booleanArrayOf",
|
||||
"kotlin.emptyArray"
|
||||
"kotlin.emptyArray",
|
||||
"kotlin.ubyteArrayOf",
|
||||
"kotlin.ushortArrayOf",
|
||||
"kotlin.uintArrayOf",
|
||||
"kotlin.ulongArrayOf"
|
||||
);
|
||||
|
||||
public static void checkConstructorParametersType(@NotNull List<KtParameter> parameters, @NotNull BindingTrace trace) {
|
||||
@@ -91,7 +95,8 @@ public class CompileTimeConstantUtils {
|
||||
KotlinBuiltIns.isPrimitiveArray(parameterType) ||
|
||||
KotlinBuiltIns.isPrimitiveType(parameterType) ||
|
||||
KotlinBuiltIns.isString(parameterType) ||
|
||||
UnsignedTypes.INSTANCE.isUnsignedType(parameterType)) {
|
||||
UnsignedTypes.isUnsignedType(parameterType) ||
|
||||
UnsignedTypes.isUnsignedArrayType(parameterType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// WITH_REFLECT
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
annotation class AnnoUB(val ub: UByteArray)
|
||||
annotation class AnnoUS(val us: UShortArray)
|
||||
annotation class AnnoUI(val ui: UIntArray)
|
||||
annotation class AnnoUL(val ul: ULongArray)
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
const val ub0 = UByte(1)
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
const val us0 = UShort(2)
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
const val ul0 = ULong(3)
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
const val ui0 = UInt(-1)
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
const val ui1 = UInt(0)
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
const val ui2 = UInt(40 + 2)
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
object Foo {
|
||||
@AnnoUB([UByte(1), ub0])
|
||||
fun f0() {}
|
||||
|
||||
@AnnoUS([UShort(2 + 5), us0])
|
||||
fun f1() {}
|
||||
|
||||
@AnnoUI([ui0, ui1, ui2, UInt(100)])
|
||||
fun f2() {}
|
||||
|
||||
@AnnoUL([ul0, ULong(5)])
|
||||
fun f3() {}
|
||||
}
|
||||
|
||||
fun <T> check(ann: Annotation, f: T.() -> Boolean) {
|
||||
val result = (ann as T).f()
|
||||
if (!result) throw RuntimeException("fail for $ann")
|
||||
}
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
fun box(): String {
|
||||
if (ub0.toByte() != 1.toByte()) return "fail"
|
||||
if (us0.toShort() != 2.toShort()) return "fail"
|
||||
if (ul0.toLong() != 3L) return "fail"
|
||||
if ((ui0 + ui1 + ui2).toInt() != 41) return "fail"
|
||||
|
||||
check<AnnoUB>(Foo::f0.annotations.first()) {
|
||||
this.ub[0] == UByte(1) && this.ub[1] == UByte(1)
|
||||
}
|
||||
|
||||
check<AnnoUS>(Foo::f1.annotations.first()) {
|
||||
this.us[0] == UShort(7) && this.us[1] == UShort(2)
|
||||
}
|
||||
|
||||
check<AnnoUI>(Foo::f2.annotations.first()) {
|
||||
this.ui[0] == UInt.MAX_VALUE && this.ui[1] == UInt(0) && this.ui[2] == UInt(42) && this.ui[3] == UInt(100)
|
||||
}
|
||||
|
||||
check<AnnoUL>(Foo::f3.annotations.first()) {
|
||||
this.ul[0] == ULong(3) && this.ul[1] == ULong(5)
|
||||
}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
// WITH_RUNTIME
|
||||
|
||||
annotation class Ann(
|
||||
val u: UInt,
|
||||
val uba: UByteArray,
|
||||
val usa: UShortArray,
|
||||
val uia: UIntArray,
|
||||
val ula: ULongArray
|
||||
)
|
||||
|
||||
@Ann(
|
||||
1u,
|
||||
[1u],
|
||||
ushortArrayOf(),
|
||||
[1u, 1u],
|
||||
ulongArrayOf(1u, 1u)
|
||||
)
|
||||
fun foo() {}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
@java.lang.annotation.Retention
|
||||
@kotlin.Metadata
|
||||
public annotation class Ann {
|
||||
// source: 'annotationGetters.kt'
|
||||
public abstract method u(): int
|
||||
public abstract method uba(): byte[]
|
||||
public abstract method uia(): int[]
|
||||
public abstract method ula(): long[]
|
||||
public abstract method usa(): short[]
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class AnnotationGettersKt {
|
||||
// source: 'annotationGetters.kt'
|
||||
public final static @Ann method foo(): void
|
||||
}
|
||||
+1
-1
@@ -7,6 +7,6 @@ fun ulong(vararg a: ULong) {}
|
||||
|
||||
class ValueParam(vararg val a: ULong)
|
||||
|
||||
annotation class Ann(vararg val a: <!INVALID_TYPE_OF_ANNOTATION_MEMBER!>UInt<!>)
|
||||
annotation class Ann(vararg val a: UInt)
|
||||
|
||||
fun array(<!FORBIDDEN_VARARG_PARAMETER_TYPE!>vararg<!> a: UIntArray) {}
|
||||
|
||||
+5
@@ -33900,6 +33900,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/equalsImplForInlineClassWrappingNullableInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("evaluateConstructorOfUnsignedArrayType.kt")
|
||||
public void testEvaluateConstructorOfUnsignedArrayType() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/evaluateConstructorOfUnsignedArrayType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("evaluateConstructorOfUnsignedType.kt")
|
||||
public void testEvaluateConstructorOfUnsignedType() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/evaluateConstructorOfUnsignedType.kt");
|
||||
|
||||
+5
@@ -975,6 +975,11 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/annotatedPropertyWithInlineClassTypeInSignature.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationGetters.kt")
|
||||
public void testAnnotationGetters() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/annotationGetters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationsOnHiddenConstructor.kt")
|
||||
public void testAnnotationsOnHiddenConstructor() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/annotationsOnHiddenConstructor.kt");
|
||||
|
||||
+5
@@ -31534,6 +31534,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/equalsImplForInlineClassWrappingNullableInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("evaluateConstructorOfUnsignedArrayType.kt")
|
||||
public void testEvaluateConstructorOfUnsignedArrayType() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/evaluateConstructorOfUnsignedArrayType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("evaluateConstructorOfUnsignedType.kt")
|
||||
public void testEvaluateConstructorOfUnsignedType() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/evaluateConstructorOfUnsignedType.kt");
|
||||
|
||||
+5
@@ -32129,6 +32129,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/equalsImplForInlineClassWrappingNullableInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("evaluateConstructorOfUnsignedArrayType.kt")
|
||||
public void testEvaluateConstructorOfUnsignedArrayType() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/evaluateConstructorOfUnsignedArrayType.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("evaluateConstructorOfUnsignedType.kt")
|
||||
public void testEvaluateConstructorOfUnsignedType() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/unsignedTypes/evaluateConstructorOfUnsignedType.kt");
|
||||
|
||||
+5
@@ -945,6 +945,11 @@ public class IrBytecodeListingTestGenerated extends AbstractIrBytecodeListingTes
|
||||
runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/annotatedPropertyWithInlineClassTypeInSignature.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationGetters.kt")
|
||||
public void testAnnotationGetters() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/annotationGetters.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("annotationsOnHiddenConstructor.kt")
|
||||
public void testAnnotationsOnHiddenConstructor() throws Exception {
|
||||
runTest("compiler/testData/codegen/bytecodeListing/inlineClasses/annotationsOnHiddenConstructor.kt");
|
||||
|
||||
@@ -153,6 +153,10 @@ object StandardNames {
|
||||
@JvmField val uShort: ClassId = ClassId.topLevel(uShortFqName)
|
||||
@JvmField val uInt: ClassId = ClassId.topLevel(uIntFqName)
|
||||
@JvmField val uLong: ClassId = ClassId.topLevel(uLongFqName)
|
||||
@JvmField val uByteArrayFqName: FqName = fqName("UByteArray")
|
||||
@JvmField val uShortArrayFqName: FqName = fqName("UShortArray")
|
||||
@JvmField val uIntArrayFqName: FqName = fqName("UIntArray")
|
||||
@JvmField val uLongArrayFqName: FqName = fqName("ULongArray")
|
||||
|
||||
@JvmField val primitiveTypeShortNames: Set<Name> = newHashSetWithExpectedSize<Name>(PrimitiveType.values().size).apply {
|
||||
PrimitiveType.values().mapTo(this) { it.typeName }
|
||||
|
||||
@@ -819,6 +819,26 @@ public abstract class KotlinBuiltIns {
|
||||
return isConstructedFromGivenClassAndNotNullable(type, FqNames.uLongFqName.toUnsafe());
|
||||
}
|
||||
|
||||
public static boolean isUByteArray(@NotNull KotlinType type) {
|
||||
return isConstructedFromGivenClassAndNotNullable(type, FqNames.uByteArrayFqName.toUnsafe());
|
||||
}
|
||||
|
||||
public static boolean isUShortArray(@NotNull KotlinType type) {
|
||||
return isConstructedFromGivenClassAndNotNullable(type, FqNames.uShortArrayFqName.toUnsafe());
|
||||
}
|
||||
|
||||
public static boolean isUIntArray(@NotNull KotlinType type) {
|
||||
return isConstructedFromGivenClassAndNotNullable(type, FqNames.uIntArrayFqName.toUnsafe());
|
||||
}
|
||||
|
||||
public static boolean isULongArray(@NotNull KotlinType type) {
|
||||
return isConstructedFromGivenClassAndNotNullable(type, FqNames.uLongArrayFqName.toUnsafe());
|
||||
}
|
||||
|
||||
public static boolean isUnsignedArrayType(@NotNull KotlinType type) {
|
||||
return isUByteArray(type) || isUShortArray(type) || isUIntArray(type) || isULongArray(type);
|
||||
}
|
||||
|
||||
public static boolean isDoubleOrNullableDouble(@NotNull KotlinType type) {
|
||||
return isConstructedFromGivenClass(type, FqNames._double);
|
||||
}
|
||||
|
||||
@@ -23,10 +23,26 @@ enum class UnsignedType(val classId: ClassId) {
|
||||
val arrayClassId = ClassId(classId.packageFqName, Name.identifier(typeName.asString() + "Array"))
|
||||
}
|
||||
|
||||
enum class UnsignedArrayType(val classId: ClassId) {
|
||||
UBYTEARRAY(ClassId.fromString("kotlin/UByteArray")),
|
||||
USHORTARRAY(ClassId.fromString("kotlin/UShortArray")),
|
||||
UINTARRAY(ClassId.fromString("kotlin/UIntArray")),
|
||||
ULONGARRAY(ClassId.fromString("kotlin/ULongArray"));
|
||||
|
||||
val typeName = classId.shortClassName
|
||||
}
|
||||
|
||||
object UnsignedTypes {
|
||||
private val unsignedTypeNames = enumValues<UnsignedType>().map { it.typeName }.toSet()
|
||||
private val unsignedArrayTypeNames = enumValues<UnsignedArrayType>().map { it.typeName }.toSet()
|
||||
private val arrayClassIdToUnsignedClassId = hashMapOf<ClassId, ClassId>()
|
||||
private val unsignedClassIdToArrayClassId = hashMapOf<ClassId, ClassId>()
|
||||
val unsignedArrayTypeToArrayCall = hashMapOf(
|
||||
UnsignedArrayType.UBYTEARRAY to Name.identifier("ubyteArrayOf"),
|
||||
UnsignedArrayType.USHORTARRAY to Name.identifier("ushortArrayOf"),
|
||||
UnsignedArrayType.UINTARRAY to Name.identifier("uintArrayOf"),
|
||||
UnsignedArrayType.ULONGARRAY to Name.identifier("ulongArrayOf"),
|
||||
)
|
||||
|
||||
private val arrayClassesShortNames: Set<Name> = UnsignedType.values().mapTo(mutableSetOf()) { it.arrayClassId.shortClassName }
|
||||
|
||||
@@ -66,4 +82,40 @@ object UnsignedTypes {
|
||||
container.fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME &&
|
||||
descriptor.name in UnsignedTypes.unsignedTypeNames
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isUnsignedArrayType(type: KotlinType): Boolean {
|
||||
if (TypeUtils.noExpectedType(type)) return false
|
||||
|
||||
val descriptor = type.constructor.declarationDescriptor ?: return false
|
||||
return isUnsignedArrayClass(descriptor)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun toUnsignedArrayType(type: KotlinType): UnsignedArrayType? =
|
||||
when {
|
||||
KotlinBuiltIns.isUByteArray(type) -> UnsignedArrayType.UBYTEARRAY
|
||||
KotlinBuiltIns.isUShortArray(type) -> UnsignedArrayType.USHORTARRAY
|
||||
KotlinBuiltIns.isUIntArray(type) -> UnsignedArrayType.UINTARRAY
|
||||
KotlinBuiltIns.isULongArray(type) -> UnsignedArrayType.ULONGARRAY
|
||||
else -> null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun toUnsignedArrayType(descriptor: DeclarationDescriptor): UnsignedArrayType? =
|
||||
if (!isUnsignedArrayClass(descriptor)) null
|
||||
else when (descriptor.name.asString()) {
|
||||
"UByteArray" -> UnsignedArrayType.UBYTEARRAY
|
||||
"UShortArray" -> UnsignedArrayType.USHORTARRAY
|
||||
"UIntArray" -> UnsignedArrayType.UINTARRAY
|
||||
"ULongArray" -> UnsignedArrayType.ULONGARRAY
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun isUnsignedArrayClass(descriptor: DeclarationDescriptor): Boolean {
|
||||
val container = descriptor.containingDeclaration
|
||||
return container is PackageFragmentDescriptor &&
|
||||
container.fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME &&
|
||||
descriptor.name in unsignedArrayTypeNames
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,11 +56,13 @@ class AnnotationValue(value: AnnotationDescriptor) : ConstantValue<AnnotationDes
|
||||
}
|
||||
|
||||
class ArrayValue(
|
||||
value: List<ConstantValue<*>>,
|
||||
private val computeType: (ModuleDescriptor) -> KotlinType
|
||||
value: List<ConstantValue<*>>,
|
||||
private val computeType: (ModuleDescriptor) -> KotlinType
|
||||
) : ConstantValue<List<ConstantValue<*>>>(value) {
|
||||
override fun getType(module: ModuleDescriptor): KotlinType = computeType(module).also { type ->
|
||||
assert(KotlinBuiltIns.isArray(type) || KotlinBuiltIns.isPrimitiveArray(type)) { "Type should be an array, but was $type: $value" }
|
||||
assert(KotlinBuiltIns.isArray(type) || KotlinBuiltIns.isPrimitiveArray(type) || KotlinBuiltIns.isUnsignedArrayType(type)) {
|
||||
"Type should be an array, but was $type: $value"
|
||||
}
|
||||
}
|
||||
|
||||
override fun <R, D> accept(visitor: AnnotationArgumentVisitor<R, D>, data: D) = visitor.visitArrayValue(this, data)
|
||||
|
||||
Reference in New Issue
Block a user