From 7f795f212ff75f3e6ac99faad239c88cac8c5c3d Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Wed, 26 Jul 2023 18:44:14 +0200 Subject: [PATCH] Support instantiation of Java annotations with defaults For annotations defined in Java, IrProperties do not contain initializers in backing fields, as annotation properties are represented as Java methods. Therefore, it is not possible to use initializer values as default values for constructor parameters. However, K2 stores default values in annotation's constructor parameters, so it is possible to fix this issue if they're properly transfered to the IR and inspected in JvmAnnotationImplementationTransformer #KT-47702 Fixed #KT-47702 tag fixed-in-k2 --- .../kotlin/fir/backend/ConversionUtils.kt | 10 +++ .../fir/backend/Fir2IrDeclarationStorage.kt | 28 ++++--- .../kotlin/fir/lazy/Fir2IrLazyConstructor.kt | 4 +- .../kotlin/fir/lazy/Fir2IrLazyProperty.kt | 8 +- ...LightTreeBlackBoxCodegenTestGenerated.java | 12 +++ .../FirPsiBlackBoxCodegenTestGenerated.java | 12 +++ .../jetbrains/kotlin/fir/java/JavaUtils.kt | 17 +++- .../kotlin/fir/java/javaAnnotationsMapping.kt | 9 ++- .../JvmAnnotationImplementationTransformer.kt | 22 ++++-- .../annotations/instances/javaAnnotation.kt | 13 +--- .../instances/javaAnnotationDefault.kt | 78 +++++++++++++++++++ .../instances/javaExistingAnnotation.kt | 31 ++++++++ .../IrBlackBoxCodegenTestGenerated.java | 12 +++ ...kBoxCodegenWithIrInlinerTestGenerated.java | 12 +++ .../LightAnalysisModeTestGenerated.java | 10 +++ .../ir/SerialInfoImplJvmIrGenerator.kt | 2 +- 16 files changed, 239 insertions(+), 41 deletions(-) create mode 100644 compiler/testData/codegen/box/annotations/instances/javaAnnotationDefault.kt create mode 100644 compiler/testData/codegen/box/annotations/instances/javaExistingAnnotation.kt diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt index c45f4ec5a43..603bdd7256e 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/ConversionUtils.kt @@ -795,3 +795,13 @@ fun FirCallableDeclaration.contextReceiversForFunctionOrContainingProperty(): Li fun IrActualizedResult?.extractFirDeclarations(): Set? { return this?.actualizedExpectDeclarations?.mapNotNullTo(mutableSetOf()) { ((it as IrMetadataSourceOwner).metadata as FirMetadataSource).fir } } + +// This method is intended to be used for default values of annotation parameters (compile-time strings, numbers, enum values, KClasses) +// where they are needed and may produce incorrect results for values that may be encountered outside annotations. +fun FirExpression.asCompileTimeIrInitializer(components: Fir2IrComponents): IrExpressionBody? { + return when (val elem = this.accept(Fir2IrVisitor(components, Fir2IrConversionScope()), null)) { + is IrExpressionBody -> elem + is IrExpression -> components.irFactory.createExpressionBody(elem) + else -> null + } +} diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt index ce702dff32a..f262d66c233 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt @@ -47,6 +47,7 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin.GeneratedByPlugi import org.jetbrains.kotlin.ir.declarations.impl.* import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyClass import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.expressions.IrSyntheticBodyKind import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl import org.jetbrains.kotlin.ir.symbols.* @@ -1346,6 +1347,11 @@ class Fir2IrDeclarationStorage( useStubForDefaultValueStub: Boolean = true, typeOrigin: ConversionTypeOrigin = ConversionTypeOrigin.DEFAULT, skipDefaultParameter: Boolean = false, + // Use this parameter if you want to insert the actual default value instead of the stub (overrides useStubForDefaultValueStub parameter). + // This parameter is intended to be used for default values of annotation parameters where they are needed and + // may produce incorrect results for values that may be encountered outside annotations. + // Does not do anything if valueParameter.defaultValue is already FirExpressionStub. + forcedDefaultValueConversion: Boolean = false, ): IrValueParameter = convertCatching(valueParameter) { val origin = valueParameter.computeIrOrigin() val type = valueParameter.returnTypeRef.toIrType(typeOrigin) @@ -1366,16 +1372,20 @@ class Fir2IrDeclarationStorage( isNoinline = valueParameter.isNoinline, isHidden = false, ).apply { - if (!skipDefaultParameter && valueParameter.defaultValue.let { - it != null && (useStubForDefaultValueStub || it !is FirExpressionStub) + val defaultValue = valueParameter.defaultValue + if (!skipDefaultParameter && defaultValue != null) { + this.defaultValue = when { + forcedDefaultValueConversion && defaultValue !is FirExpressionStub -> + defaultValue.asCompileTimeIrInitializer(components) + useStubForDefaultValueStub || defaultValue !is FirExpressionStub -> + factory.createExpressionBody( + IrErrorExpressionImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, + "Stub expression for default value of ${valueParameter.name}" + ) + ) + else -> null } - ) { - this.defaultValue = factory.createExpressionBody( - IrErrorExpressionImpl( - UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, - "Stub expression for default value of ${valueParameter.name}" - ) - ) } annotationGenerator.generate(this, valueParameter) } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyConstructor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyConstructor.kt index 7b34f2f2991..b21d254c6be 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyConstructor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyConstructor.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.ir.declarations.lazy.lazyVar import org.jetbrains.kotlin.ir.expressions.IrBody import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.util.isAnnotationClass import org.jetbrains.kotlin.ir.util.parentClassOrNull import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.name.Name @@ -110,7 +111,8 @@ class Fir2IrLazyConstructor( fir.valueParameters.mapIndexedTo(this) { index, valueParameter -> declarationStorage.createIrParameter( valueParameter, index + contextReceiverParametersCount, - useStubForDefaultValueStub = (parent as? IrClass)?.name != Name.identifier("Enum") + useStubForDefaultValueStub = (parent as? IrClass)?.name != Name.identifier("Enum"), + forcedDefaultValueConversion = (parent as? IrClass)?.isAnnotationClass == true, ).apply { this.parent = this@Fir2IrLazyConstructor } diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt index 6c8ccbe94d2..c062d739fee 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/lazy/Fir2IrLazyProperty.kt @@ -94,13 +94,7 @@ class Fir2IrLazyProperty( private fun toIrInitializer(initializer: FirExpression?): IrExpressionBody? { // Annotations need full initializer information to instantiate them correctly return when { - containingClass?.classKind?.isAnnotationClass == true -> { - when (val elem = initializer?.accept(Fir2IrVisitor(components, Fir2IrConversionScope()), null)) { - is IrExpressionBody -> elem - is IrExpression -> factory.createExpressionBody(elem) - else -> null - } - } + containingClass?.classKind?.isAnnotationClass == true -> initializer?.asCompileTimeIrInitializer(components) // Setting initializers to every other class causes some cryptic errors in lowerings initializer is FirConstExpression<*> -> { val constType = with(typeConverter) { initializer.typeRef.toIrType() } diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java index aafa7e1b231..1b3059f3b21 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeBlackBoxCodegenTestGenerated.java @@ -582,6 +582,18 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr runTest("compiler/testData/codegen/box/annotations/instances/javaAnnotation.kt"); } + @Test + @TestMetadata("javaAnnotationDefault.kt") + public void testJavaAnnotationDefault() throws Exception { + runTest("compiler/testData/codegen/box/annotations/instances/javaAnnotationDefault.kt"); + } + + @Test + @TestMetadata("javaExistingAnnotation.kt") + public void testJavaExistingAnnotation() throws Exception { + runTest("compiler/testData/codegen/box/annotations/instances/javaExistingAnnotation.kt"); + } + @Test @TestMetadata("kotlinExistingAnnotation.kt") public void testKotlinExistingAnnotation() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java index c55c8d70751..5a85d96080e 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiBlackBoxCodegenTestGenerated.java @@ -582,6 +582,18 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo runTest("compiler/testData/codegen/box/annotations/instances/javaAnnotation.kt"); } + @Test + @TestMetadata("javaAnnotationDefault.kt") + public void testJavaAnnotationDefault() throws Exception { + runTest("compiler/testData/codegen/box/annotations/instances/javaAnnotationDefault.kt"); + } + + @Test + @TestMetadata("javaExistingAnnotation.kt") + public void testJavaExistingAnnotation() throws Exception { + runTest("compiler/testData/codegen/box/annotations/instances/javaExistingAnnotation.kt"); + } + @Test @TestMetadata("kotlinExistingAnnotation.kt") public void testKotlinExistingAnnotation() throws Exception { diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt index 2df3401108f..067b4b85b9b 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaUtils.kt @@ -17,8 +17,8 @@ import org.jetbrains.kotlin.fir.expressions.builder.buildArrayLiteral import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression import org.jetbrains.kotlin.fir.expressions.builder.buildErrorExpression import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.expectedConeType +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef -import org.jetbrains.kotlin.fir.types.createArrayType import org.jetbrains.kotlin.load.java.JvmAnnotationNames import org.jetbrains.kotlin.load.java.RXJAVA3_ANNOTATIONS import org.jetbrains.kotlin.load.java.structure.JavaAnnotation @@ -54,8 +54,19 @@ val JavaClass.classKind: ClassKind fun JavaClass.hasMetadataAnnotation(): Boolean = annotations.any { it.isResolvedTo(JvmAnnotationNames.METADATA_FQ_NAME) } -internal fun Any?.createConstantOrError(session: FirSession): FirExpression { - return createConstantIfAny(session) ?: buildErrorExpression { +internal fun Any?.createConstantOrError(session: FirSession, expectedTypeRef: FirTypeRef? = null): FirExpression { + val coneType = expectedTypeRef?.coneTypeOrNull + val value = if (this is Int && coneType != null) { + // special case for Java literals in annotation default values: + // literal value is always integer, but an expected parameter type can be any other number type + when { + coneType.isByte -> this.toByte() + coneType.isShort -> this.toShort() + coneType.isLong -> this.toLong() + else -> this + } + } else this + return value.createConstantIfAny(session) ?: buildErrorExpression { diagnostic = ConeSimpleDiagnostic("Unknown value in JavaLiteralAnnotationArgument: $this", DiagnosticKind.Java) } } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/javaAnnotationsMapping.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/javaAnnotationsMapping.kt index e60f56df945..be38181aad4 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/javaAnnotationsMapping.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/javaAnnotationsMapping.kt @@ -84,7 +84,10 @@ internal fun JavaAnnotationArgument.toFirExpression( session: FirSession, javaTypeParameterStack: JavaTypeParameterStack, expectedTypeRef: FirTypeRef? ): FirExpression { return when (this) { - is JavaLiteralAnnotationArgument -> value.createConstantOrError(session) + is JavaLiteralAnnotationArgument -> value.createConstantOrError( + session, + expectedTypeRef?.resolveIfJavaType(session, javaTypeParameterStack) + ) is JavaArrayAnnotationArgument -> buildArrayLiteral { val argumentTypeRef = expectedTypeRef?.let { typeRef = if (it is FirJavaTypeRef) buildResolvedTypeRef { @@ -275,7 +278,9 @@ private fun JavaAnnotation.toFirAnnotationCall(session: FirSession): FirAnnotati classId == StandardClassIds.Annotations.Java.Deprecated -> { mapOf( - StandardClassIds.Annotations.ParameterNames.deprecatedMessage to "Deprecated in Java".createConstantOrError(session) + StandardClassIds.Annotations.ParameterNames.deprecatedMessage to "Deprecated in Java".createConstantOrError( + session, + ) ) } diff --git a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmAnnotationImplementationTransformer.kt b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmAnnotationImplementationTransformer.kt index a07bfd01227..a02f394b411 100644 --- a/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmAnnotationImplementationTransformer.kt +++ b/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmAnnotationImplementationTransformer.kt @@ -116,6 +116,7 @@ class JvmAnnotationImplementationTransformer(val jvmContext: JvmBackendContext, generatedConstructor: IrConstructor ) { implementor.implementAnnotationPropertiesAndConstructor( + annotationClass, annotationClass.getAnnotationProperties(), implClass, generatedConstructor, @@ -231,6 +232,7 @@ class JvmAnnotationImplementationTransformer(val jvmContext: JvmBackendContext, } fun implementAnnotationPropertiesAndConstructor( + annotationClass: IrClass, annotationProperties: List, implClass: IrClass, generatedConstructor: IrConstructor, @@ -248,6 +250,11 @@ class JvmAnnotationImplementationTransformer(val jvmContext: JvmBackendContext, generatedConstructor.body = ctorBody + // For annotations defined in Java, IrProperties do not contain initializers in backing fields, as annotation properties are represented as Java methods + // (that are later converted to synthetic properties w/o fields). + // However, K2 stores default values in annotation's constructor parameters. + val fallbackPrimaryCtorParamsMap = annotationClass.primaryConstructor?.valueParameters?.associateBy { it.name }.orEmpty() + annotationProperties.forEach { property -> val propType = property.getter!!.returnType val storedFieldType = propType.kClassToJClassIfNeeded() @@ -266,12 +273,15 @@ class JvmAnnotationImplementationTransformer(val jvmContext: JvmBackendContext, val defaultExpression = property.backingField?.initializer?.expression val newDefaultValue: IrExpressionBody? = - if (defaultExpression is IrGetValue && defaultExpression.symbol.owner is IrValueParameter) { - // INITIALIZE_PROPERTY_FROM_PARAMETER - (defaultExpression.symbol.owner as IrValueParameter).defaultValue - } else if (defaultExpression != null) { - property.backingField!!.initializer - } else null + // INITIALIZE_PROPERTY_FROM_PARAMETER + when { + defaultExpression is IrGetValue && defaultExpression.symbol.owner is IrValueParameter -> + (defaultExpression.symbol.owner as IrValueParameter).defaultValue + defaultExpression != null -> property.backingField!!.initializer + propName in fallbackPrimaryCtorParamsMap -> + fallbackPrimaryCtorParamsMap[propName]?.defaultValue?.takeIf { it.expression !is IrErrorExpression } + else -> null + } parameter.defaultValue = newDefaultValue?.deepCopyWithVariables() ?.also { if (defaultValueTransformer != null) it.transformChildrenVoid(defaultValueTransformer) } diff --git a/compiler/testData/codegen/box/annotations/instances/javaAnnotation.kt b/compiler/testData/codegen/box/annotations/instances/javaAnnotation.kt index 1f46c048ce4..7ee63727a0d 100644 --- a/compiler/testData/codegen/box/annotations/instances/javaAnnotation.kt +++ b/compiler/testData/codegen/box/annotations/instances/javaAnnotation.kt @@ -20,12 +20,6 @@ public @interface C { String v2(); } -// FILE: D.java - -public @interface D { - String value() default "hello"; -} - // FILE: b.kt fun box(): String { @@ -34,10 +28,5 @@ fun box(): String { assert(b.value == "OK") val c = C(v2 = "v2", v1 = intArrayOf(1)) assert(c.v2 == "v2") - // TODO(KT-47702): Looks like we have to force users either to pass default java parameters explicitly - // or hack LazyJavaClassDescriptor/JavaPropertyDescriptor to load annotation param default value, - // because it is not stored currently anywhere. - // val d = D() - val d = D("OK").value - return d + return "OK" } diff --git a/compiler/testData/codegen/box/annotations/instances/javaAnnotationDefault.kt b/compiler/testData/codegen/box/annotations/instances/javaAnnotationDefault.kt new file mode 100644 index 00000000000..27accb6bff3 --- /dev/null +++ b/compiler/testData/codegen/box/annotations/instances/javaAnnotationDefault.kt @@ -0,0 +1,78 @@ +// TARGET_BACKEND: JVM_IR +// IGNORE_BACKEND_K1: JVM_IR + +// WITH_STDLIB +// !LANGUAGE: +InstantiationOfAnnotationClasses + +// FILE: A.java +public @interface A { + String value() default "OK"; +} + +// FILE: ChildAnnotation.java +@interface ChildAnnotation { + String value(); +} + +// FILE: D.java +public @interface D { + //Primitive types + boolean booleanValue() default false; + byte byteValue() default 1; + short shortValue() default 2; + int intValue() default 3; + long longValue() default 4; + float floatValue() default 5.0f; + double doubleValue() default 6.0; + char charValue() default 'a'; + + // String + String stringValue() default "default"; + + // Class type + Class classValue() default Object.class; + + // Enum type + MyEnum enumValue() default MyEnum.FIRST; + + // Annotation + ChildAnnotation annotationValue() default @ChildAnnotation(value = "child") ; + + // Arrays of the above + boolean[] booleanArrayValue() default { false, true }; + byte[] byteArrayValue() default { 1, 2 }; + short[] shortArrayValue() default { 3, 4 }; + int[] intArrayValue() default { 5, 6 }; + long[] longArrayValue() default { 7, 8 }; + float[] floatArrayValue() default { 9.0f, 10.0f }; + double[] doubleArrayValue() default { 11.0, 12.0 }; + char[] charArrayValue() default { 'x', 'y' }; + String[] stringArrayValue() default { "Hello", "World" }; + Class[] classArrayValue() default { Object.class, String.class }; + MyEnum[] enumArrayValue() default { MyEnum.FIRST, MyEnum.SECOND }; + ChildAnnotation[] annotationArrayValue() default { @ChildAnnotation(value = "child1"), @ChildAnnotation(value = "child2") }; + + // other annotation with default value + A annotationWithDefault() default @A; +} + +// Supporting enum +enum MyEnum { FIRST, SECOND } + +// FILE: b.kt + +fun box(): String { + val d = D() + val str = d.toString() + val golden = """@D(booleanValue=false, byteValue=1, shortValue=2, intValue=3, longValue=4, floatValue=5.0, doubleValue=6.0, charValue=a, stringValue=default, """+ + """classValue=class java.lang.Object, enumValue=FIRST, annotationValue=@ChildAnnotation(value=child), booleanArrayValue=[false, true], byteArrayValue=[1, 2], """ + + """shortArrayValue=[3, 4], intArrayValue=[5, 6], longArrayValue=[7, 8], floatArrayValue=[9.0, 10.0], doubleArrayValue=[11.0, 12.0], charArrayValue=[x, y], stringArrayValue=[Hello, World], """ + + """classArrayValue=[class java.lang.Object, class java.lang.String], enumArrayValue=[FIRST, SECOND], annotationArrayValue=[@ChildAnnotation(value=child1), @ChildAnnotation(value=child2)], """ + + """annotationWithDefault=@A(value=OK))""" + if (str != golden) return str + if (d.longValue != 4L) return d.longValue.toString() + if (d.annotationValue.value != "child") return d.annotationValue.value + if (d.doubleArrayValue[0] != 11.0) return d.doubleArrayValue[0].toString() + if (d.classArrayValue[1] != String::class) return d.classArrayValue.contentToString() + return d.annotationWithDefault.value +} diff --git a/compiler/testData/codegen/box/annotations/instances/javaExistingAnnotation.kt b/compiler/testData/codegen/box/annotations/instances/javaExistingAnnotation.kt new file mode 100644 index 00000000000..f0f3378600f --- /dev/null +++ b/compiler/testData/codegen/box/annotations/instances/javaExistingAnnotation.kt @@ -0,0 +1,31 @@ +// TARGET_BACKEND: JVM_IR +// IGNORE_BACKEND_K1: JVM_IR +// IGNORE_DEXING +// WITH_STDLIB +// !LANGUAGE: +InstantiationOfAnnotationClasses + +// MODULE: lib +// FILE: LibAnnotation.java + +package a; + +public @interface LibAnnotation { + long longValue() default 4; + String stringValue() default "OK"; + Class classValue() default String.class; + float[] floatArrayValue() default { 9.0f, 10.0f }; +} + +// MODULE: app(lib) +// FILE: app.kt + +package test + +import a.* + +fun box(): String { + val l = LibAnnotation() + if (l.toString() != "@a.LibAnnotation(longValue=4, stringValue=OK, classValue=class java.lang.String, floatArrayValue=[9.0, 10.0])") + return l.toString() + return "OK" +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 6b71976d76f..74d1d74e2fa 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -582,6 +582,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/annotations/instances/javaAnnotation.kt"); } + @Test + @TestMetadata("javaAnnotationDefault.kt") + public void testJavaAnnotationDefault() throws Exception { + runTest("compiler/testData/codegen/box/annotations/instances/javaAnnotationDefault.kt"); + } + + @Test + @TestMetadata("javaExistingAnnotation.kt") + public void testJavaExistingAnnotation() throws Exception { + runTest("compiler/testData/codegen/box/annotations/instances/javaExistingAnnotation.kt"); + } + @Test @TestMetadata("kotlinExistingAnnotation.kt") public void testKotlinExistingAnnotation() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java index dd4897b57fa..0e557ba362e 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenWithIrInlinerTestGenerated.java @@ -582,6 +582,18 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack runTest("compiler/testData/codegen/box/annotations/instances/javaAnnotation.kt"); } + @Test + @TestMetadata("javaAnnotationDefault.kt") + public void testJavaAnnotationDefault() throws Exception { + runTest("compiler/testData/codegen/box/annotations/instances/javaAnnotationDefault.kt"); + } + + @Test + @TestMetadata("javaExistingAnnotation.kt") + public void testJavaExistingAnnotation() throws Exception { + runTest("compiler/testData/codegen/box/annotations/instances/javaExistingAnnotation.kt"); + } + @Test @TestMetadata("kotlinExistingAnnotation.kt") public void testKotlinExistingAnnotation() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 1374ab153c8..33cceb0f173 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -430,6 +430,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/annotations/instances/innerAnnotationInstantiation.kt"); } + @TestMetadata("javaAnnotationDefault.kt") + public void ignoreJavaAnnotationDefault() throws Exception { + runTest("compiler/testData/codegen/box/annotations/instances/javaAnnotationDefault.kt"); + } + + @TestMetadata("javaExistingAnnotation.kt") + public void ignoreJavaExistingAnnotation() throws Exception { + runTest("compiler/testData/codegen/box/annotations/instances/javaExistingAnnotation.kt"); + } + private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); } diff --git a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerialInfoImplJvmIrGenerator.kt b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerialInfoImplJvmIrGenerator.kt index b0ca0263583..f2b756caffb 100644 --- a/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerialInfoImplJvmIrGenerator.kt +++ b/plugins/kotlinx-serialization/kotlinx-serialization.backend/src/org/jetbrains/kotlinx/serialization/compiler/backend/ir/SerialInfoImplJvmIrGenerator.kt @@ -91,7 +91,7 @@ class SerialInfoImplJvmIrGenerator( visibility = DescriptorVisibilities.PUBLIC } - implementor.implementAnnotationPropertiesAndConstructor(properties, subclass, ctor, null) + implementor.implementAnnotationPropertiesAndConstructor(annotationClass, properties, subclass, ctor, null) } private fun createPackage(packageName: String): IrPackageFragment =