diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 70428d3df36..1c0a28e5620 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -429,6 +429,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/annotations/typeAnnotations/checkingNotincorporatedInputTypes.kt"); } + @Test + @TestMetadata("functionTypeParameterBound.kt") + public void testFunctionTypeParameterBound() throws Exception { + runTest("compiler/testData/codegen/box/annotations/typeAnnotations/functionTypeParameterBound.kt"); + } + @Test @TestMetadata("implicitReturn.kt") public void testImplicitReturn() throws Exception { @@ -453,6 +459,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/annotations/typeAnnotations/methodParameters.kt"); } + @Test + @TestMetadata("methodTypeParameters.kt") + public void testMethodTypeParameters() throws Exception { + runTest("compiler/testData/codegen/box/annotations/typeAnnotations/methodTypeParameters.kt"); + } + @Test @TestMetadata("typeAnnotationTarget6.kt") public void testTypeAnnotationTarget6() throws Exception { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt index 94958d2ccbf..d335d2be042 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt @@ -53,6 +53,8 @@ fun IrType.isTypeParameter() = classifierOrNull is IrTypeParameterSymbol fun IrType.isInterface() = classOrNull?.owner?.kind == ClassKind.INTERFACE +fun IrType.isAnnotation() = classOrNull?.owner?.kind == ClassKind.ANNOTATION_CLASS + fun IrType.isFunctionOrKFunction() = isFunction() || isKFunction() fun IrType.isSuspendFunctionOrKFunction() = isSuspendFunction() || isKSuspendFunction() diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt index 9a390971614..2a2d2ba7cf0 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/AnnotationCodegen.kt @@ -336,7 +336,7 @@ abstract class AnnotationCodegen( val IrConstructorCall.annotationClass get() = symbol.owner.parentAsClass } - private fun generateTypeAnnotations( + internal fun generateTypeAnnotations( annotated: IrAnnotationContainer, type: IrType? ) { diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt index c1de34f2606..826d92a1303 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/FunctionCodegen.kt @@ -20,6 +20,8 @@ import org.jetbrains.kotlin.codegen.inline.wrapWithMaxLocalCalc import org.jetbrains.kotlin.codegen.mangleNameIfNeeded import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.visitAnnotableParameterCount +import org.jetbrains.kotlin.config.JVMConfigurationKeys +import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.descriptors.Modality @@ -37,6 +39,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.org.objectweb.asm.* +import org.jetbrains.org.objectweb.asm.TypeReference.METHOD_TYPE_PARAMETER_BOUND import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.tree.MethodNode @@ -46,6 +49,7 @@ class FunctionCodegen( private val inlinedInto: ExpressionCodegen? = null ) { private val context = classCodegen.context + val emitTypeAnnotations = context.state.configuration.getBoolean(JVMConfigurationKeys.EMIT_JVM_TYPE_ANNOTATIONS) fun generate(): SMAPAndMethodNode = try { @@ -89,6 +93,54 @@ class FunctionCodegen( ) } }.genAnnotations(irFunction, signature.asmMethod.returnType, irFunction.returnType) + + if (context.state.target != JvmTarget.JVM_1_6) { + irFunction.typeParameters.forEachIndexed { index, typeParameter -> + object : AnnotationCodegen(classCodegen, context, true) { + override fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor { + return methodVisitor.visitTypeAnnotation( + TypeReference.newTypeParameterReference(TypeReference.METHOD_TYPE_PARAMETER, index).value, + null, + descr, + visible + ) + } + + override fun visitTypeAnnotation(descr: String?, path: TypePath?, visible: Boolean): AnnotationVisitor { + throw RuntimeException( + "Error during generation: type annotation shouldn't be presented on type parameter: " + + "${ir2string(typeParameter)} in ${ir2string(irFunction)}" + ) + } + }.genAnnotations(typeParameter, null, null) + + if (emitTypeAnnotations) { + var superInterfaceIndex = 1 + typeParameter.superTypes.forEach { superType -> + val isClassOrTypeParameter = !superType.isInterface() && !superType.isAnnotation() + val superIndex = if (isClassOrTypeParameter) 0 else superInterfaceIndex++ + object : AnnotationCodegen(classCodegen, context, true) { + override fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor { + throw RuntimeException( + "Error during generation: only type annotations should be presented on type parameters bounds: " + + "${ir2string(typeParameter)} in ${ir2string(typeParameter)}" + ) + } + + override fun visitTypeAnnotation(descr: String?, path: TypePath?, visible: Boolean): AnnotationVisitor { + return methodVisitor.visitTypeAnnotation( + TypeReference.newTypeParameterBoundReference(METHOD_TYPE_PARAMETER_BOUND, index, superIndex).value, + path, + descr, + visible + ) + } + }.generateTypeAnnotations(irFunction, superType) + } + } + } + } + if (shouldGenerateAnnotationsOnValueParameters()) { generateParameterAnnotations(irFunction, methodVisitor, signature, classCodegen, context, skipNullabilityAnnotations) } diff --git a/compiler/testData/codegen/asmLike/typeAnnotations/dontEmit.kt b/compiler/testData/codegen/asmLike/typeAnnotations/dontEmit.kt new file mode 100644 index 00000000000..6505fa58d22 --- /dev/null +++ b/compiler/testData/codegen/asmLike/typeAnnotations/dontEmit.kt @@ -0,0 +1,23 @@ +// KOTLIN_CONFIGURATION_FLAGS: -JVM.EMIT_JVM_TYPE_ANNOTATIONS +// RENDER_ANNOTATIONS +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +package foo + +@Target(AnnotationTarget.TYPE) +annotation class TypeAnn(val name: String) + +@Target(AnnotationTarget.TYPE_PARAMETER) +annotation class TypeParameterAnn(val name: String) + + +class Kotlin { + + fun foo(s: @TypeAnn("1") String) { + } + + fun bar(p: T): T { + return p + } + +} diff --git a/compiler/testData/codegen/asmLike/typeAnnotations/dontEmit.txt b/compiler/testData/codegen/asmLike/typeAnnotations/dontEmit.txt new file mode 100644 index 00000000000..81c1c424b5e --- /dev/null +++ b/compiler/testData/codegen/asmLike/typeAnnotations/dontEmit.txt @@ -0,0 +1,19 @@ +public final class foo/Kotlin : java/lang/Object { + public void () + + (TT;)TT; + public final java.lang.Object bar(java.lang.Object p) + @Lorg/jetbrains/annotations/NotNull;([]) // invisible + @Lorg/jetbrains/annotations/NotNull;([]) // invisible, parameter 0 + + public final void foo(java.lang.String s) + @Lorg/jetbrains/annotations/NotNull;([]) // invisible, parameter 0 +} + +public abstract interface foo/TypeAnn : java/lang/Object, java/lang/annotation/Annotation { + public abstract java.lang.String name() +} + +public abstract interface foo/TypeParameterAnn : java/lang/Object, java/lang/annotation/Annotation { + public abstract java.lang.String name() +} \ No newline at end of file diff --git a/compiler/testData/codegen/asmLike/typeAnnotations/functionTypeParameter.kt b/compiler/testData/codegen/asmLike/typeAnnotations/functionTypeParameter.kt new file mode 100644 index 00000000000..131a7a99526 --- /dev/null +++ b/compiler/testData/codegen/asmLike/typeAnnotations/functionTypeParameter.kt @@ -0,0 +1,62 @@ +// IGNORE_BACKEND: JVM +// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS +// RENDER_ANNOTATIONS +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +package foo + +@Target(AnnotationTarget.TYPE) +annotation class TypeAnn(val name: String) + +@Target(AnnotationTarget.TYPE) +annotation class ClassTypeAnn(val name: String) + +@Target(AnnotationTarget.TYPE) +@Retention(AnnotationRetention.BINARY) +annotation class TypeAnnBinary + +@Target(AnnotationTarget.TYPE) +@Retention(AnnotationRetention.SOURCE) +annotation class TypeAnnSource + +@Target( AnnotationTarget.TYPE_PARAMETER) +annotation class TypeParameterAnn(val name: String) + +@Target(AnnotationTarget.TYPE_PARAMETER) +@Retention(AnnotationRetention.BINARY) +annotation class TypeParameterAnnBinary + +@Target(AnnotationTarget.TYPE_PARAMETER) +@Retention(AnnotationRetention.SOURCE) +annotation class TypeParameterAnnSource + +interface Generic +class GenericClass +class B + +class Kotlin { + + fun <@TypeParameterAnn("TP1") @TypeParameterAnnBinary @TypeParameterAnnSource T, @TypeParameterAnn("TP2") @TypeParameterAnnBinary @TypeParameterAnnSource T2> typeParameter() { + } + + fun <@TypeParameterAnn("TP") T> genericParameterAndReturn(s: @TypeAnn("1") @TypeAnnBinary @TypeAnnSource T): @TypeAnn("2") @TypeAnnBinary @TypeAnnSource T { + return s + } + + fun <@TypeParameterAnn("Y") Y, @TypeParameterAnn("T") T: @TypeAnn("Generic") @TypeAnnBinary @TypeAnnSource Generic<@TypeAnn("Generic Argument") @TypeAnnBinary @TypeAnnSource Y>> genericInterfaceBound() { + } + + fun <@TypeParameterAnn("Y") Y, @TypeParameterAnn("T") T: @TypeAnn("Generic") @TypeAnnBinary @TypeAnnSource GenericClass<@TypeAnn("Generic Argument") @TypeAnnBinary @TypeAnnSource Y>> genericClassBound() { + } + + fun <@TypeParameterAnn("Y") Y, @TypeParameterAnn("T") T: @TypeAnn("Generic") Generic<@TypeAnn("Generic Argument") Y>> whereClause() where T : @ClassTypeAnn("Any") Any { + + } + + fun <@TypeParameterAnn("Y") Y, @TypeParameterAnn("T") T: @TypeAnn("Y as Bound") @TypeAnnBinary @TypeAnnSource Y> typeParameterTypeParameterBound() { + } + + // Second annotation is missed: see KT-46483, remove this test after prohibition of such cases + fun <@TypeParameterAnn("T") T: Any> whereClauseWithAnnotation() where @TypeParameterAnn("Additional") T : Generic { + } +} diff --git a/compiler/testData/codegen/asmLike/typeAnnotations/functionTypeParameter.txt b/compiler/testData/codegen/asmLike/typeAnnotations/functionTypeParameter.txt new file mode 100644 index 00000000000..d2507018245 --- /dev/null +++ b/compiler/testData/codegen/asmLike/typeAnnotations/functionTypeParameter.txt @@ -0,0 +1,98 @@ +Ljava/lang/Object; +public final class foo/B : java/lang/Object { + public void () +} + +public abstract interface foo/ClassTypeAnn : java/lang/Object, java/lang/annotation/Annotation { + public abstract java.lang.String name() +} + +Ljava/lang/Object; +public abstract interface foo/Generic : java/lang/Object { + +} + +Ljava/lang/Object; +public final class foo/GenericClass : java/lang/Object { + public void () +} + +public final class foo/Kotlin : java/lang/Object { + public void () + + ;>()V + public final void genericClassBound() + @Lfoo/TypeParameterAnn;([name="Y"]) : METHOD_TYPE_PARAMETER 0, null + @Lfoo/TypeParameterAnn;([name="T"]) : METHOD_TYPE_PARAMETER 1, null + @Lfoo/TypeAnn;([name="Generic"]) : METHOD_TYPE_PARAMETER_BOUND 1, 0, null + @Lfoo/TypeAnn;([name="Generic Argument"]) : METHOD_TYPE_PARAMETER_BOUND 1, 0, 0; + @Lfoo/TypeAnnBinary;([]) : METHOD_TYPE_PARAMETER_BOUND 1, 0, null // invisible + @Lfoo/TypeAnnBinary;([]) : METHOD_TYPE_PARAMETER_BOUND 1, 0, 0; // invisible + + ;>()V + public final void genericInterfaceBound() + @Lfoo/TypeParameterAnn;([name="Y"]) : METHOD_TYPE_PARAMETER 0, null + @Lfoo/TypeParameterAnn;([name="T"]) : METHOD_TYPE_PARAMETER 1, null + @Lfoo/TypeAnn;([name="Generic"]) : METHOD_TYPE_PARAMETER_BOUND 1, 1, null + @Lfoo/TypeAnn;([name="Generic Argument"]) : METHOD_TYPE_PARAMETER_BOUND 1, 1, 0; + @Lfoo/TypeAnnBinary;([]) : METHOD_TYPE_PARAMETER_BOUND 1, 1, null // invisible + @Lfoo/TypeAnnBinary;([]) : METHOD_TYPE_PARAMETER_BOUND 1, 1, 0; // invisible + + (TT;)TT; + public final java.lang.Object genericParameterAndReturn(java.lang.Object s) + @Lfoo/TypeAnn;([name="2"]) : METHOD_RETURN, null + @Lfoo/TypeParameterAnn;([name="TP"]) : METHOD_TYPE_PARAMETER 0, null + @Lfoo/TypeAnn;([name="1"]) : METHOD_FORMAL_PARAMETER 0, null + @Lfoo/TypeAnnBinary;([]) : METHOD_RETURN, null // invisible + @Lfoo/TypeAnnBinary;([]) : METHOD_FORMAL_PARAMETER 0, null // invisible + + ()V + public final void typeParameter() + @Lfoo/TypeParameterAnn;([name="TP1"]) : METHOD_TYPE_PARAMETER 0, null + @Lfoo/TypeParameterAnn;([name="TP2"]) : METHOD_TYPE_PARAMETER 1, null + @Lfoo/TypeParameterAnnBinary;([]) : METHOD_TYPE_PARAMETER 0, null // invisible + @Lfoo/TypeParameterAnnBinary;([]) : METHOD_TYPE_PARAMETER 1, null // invisible + + ()V + public final void typeParameterTypeParameterBound() + @Lfoo/TypeParameterAnn;([name="Y"]) : METHOD_TYPE_PARAMETER 0, null + @Lfoo/TypeParameterAnn;([name="T"]) : METHOD_TYPE_PARAMETER 1, null + @Lfoo/TypeAnn;([name="Y as Bound"]) : METHOD_TYPE_PARAMETER_BOUND 1, 0, null + @Lfoo/TypeAnnBinary;([]) : METHOD_TYPE_PARAMETER_BOUND 1, 0, null // invisible + + ;>()V + public final void whereClause() + @Lfoo/TypeParameterAnn;([name="Y"]) : METHOD_TYPE_PARAMETER 0, null + @Lfoo/TypeParameterAnn;([name="T"]) : METHOD_TYPE_PARAMETER 1, null + @Lfoo/TypeAnn;([name="Generic"]) : METHOD_TYPE_PARAMETER_BOUND 1, 1, null + @Lfoo/TypeAnn;([name="Generic Argument"]) : METHOD_TYPE_PARAMETER_BOUND 1, 1, 0; + @Lfoo/ClassTypeAnn;([name="Any"]) : METHOD_TYPE_PARAMETER_BOUND 1, 0, null + + ;>()V + public final void whereClauseWithAnnotation() + @Lfoo/TypeParameterAnn;([name="T"]) : METHOD_TYPE_PARAMETER 0, null +} + +public abstract interface foo/TypeAnn : java/lang/Object, java/lang/annotation/Annotation { + public abstract java.lang.String name() +} + +public abstract interface foo/TypeAnnBinary : java/lang/Object, java/lang/annotation/Annotation { + +} + +public abstract interface foo/TypeAnnSource : java/lang/Object, java/lang/annotation/Annotation { + +} + +public abstract interface foo/TypeParameterAnn : java/lang/Object, java/lang/annotation/Annotation { + public abstract java.lang.String name() +} + +public abstract interface foo/TypeParameterAnnBinary : java/lang/Object, java/lang/annotation/Annotation { + +} + +public abstract interface foo/TypeParameterAnnSource : java/lang/Object, java/lang/annotation/Annotation { + +} diff --git a/compiler/testData/codegen/asmLike/typeAnnotations/notYetSupported.kt b/compiler/testData/codegen/asmLike/typeAnnotations/notYetSupported.kt index 622e1f5cb3f..6fe306d28c2 100644 --- a/compiler/testData/codegen/asmLike/typeAnnotations/notYetSupported.kt +++ b/compiler/testData/codegen/asmLike/typeAnnotations/notYetSupported.kt @@ -52,5 +52,7 @@ class Kotlin { fun fooGenericOut(s: @Ann Bar) { } + fun >> innerClassInBound() { + } } diff --git a/compiler/testData/codegen/asmLike/typeAnnotations/notYetSupported.txt b/compiler/testData/codegen/asmLike/typeAnnotations/notYetSupported.txt index e573f01d14f..78bc92df62d 100644 --- a/compiler/testData/codegen/asmLike/typeAnnotations/notYetSupported.txt +++ b/compiler/testData/codegen/asmLike/typeAnnotations/notYetSupported.txt @@ -58,6 +58,9 @@ public final class foo/Kotlin : java/lang/Object { public final void fooGenericOut(foo.Bar s) @Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null @Lorg/jetbrains/annotations/NotNull;([]) // invisible, parameter 0 + + ;>;>()V + public final void innerClassInBound() } Ljava/lang/Object; @@ -70,4 +73,4 @@ public final class foo/Outer$Inner : java/lang/Object { public final class foo/Outer : java/lang/Object { public void () -} +} \ No newline at end of file diff --git a/compiler/testData/codegen/asmLike/typeAnnotations/propertyTypeParameter.kt b/compiler/testData/codegen/asmLike/typeAnnotations/propertyTypeParameter.kt new file mode 100644 index 00000000000..e6f709dc177 --- /dev/null +++ b/compiler/testData/codegen/asmLike/typeAnnotations/propertyTypeParameter.kt @@ -0,0 +1,21 @@ +// IGNORE_BACKEND: JVM +// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS +// RENDER_ANNOTATIONS +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +package foo + +@Target(AnnotationTarget.TYPE) +annotation class TypeAnn(val name: String) + +@Target( AnnotationTarget.TYPE_PARAMETER) +annotation class TypeParameterAnn() + +interface Simple + +class Kotlin { + + var <@TypeParameterAnn T: @TypeAnn("Simple") Simple> T.z: T? + get() = null + set(value) {} +} diff --git a/compiler/testData/codegen/asmLike/typeAnnotations/propertyTypeParameter.txt b/compiler/testData/codegen/asmLike/typeAnnotations/propertyTypeParameter.txt new file mode 100644 index 00000000000..53f6ddc2b99 --- /dev/null +++ b/compiler/testData/codegen/asmLike/typeAnnotations/propertyTypeParameter.txt @@ -0,0 +1,29 @@ +public final class foo/Kotlin : java/lang/Object { + public void () + + (TT;)TT; + public final foo.Simple getZ(foo.Simple $this$z) + @Lorg/jetbrains/annotations/Nullable;([]) // invisible + @Lfoo/TypeParameterAnn;([]) : METHOD_TYPE_PARAMETER 0, null + @Lfoo/TypeAnn;([name="Simple"]) : METHOD_TYPE_PARAMETER_BOUND 0, 1, null + @Lorg/jetbrains/annotations/NotNull;([]) // invisible, parameter 0 + + (TT;TT;)V + public final void setZ(foo.Simple $this$z, foo.Simple value) + @Lfoo/TypeParameterAnn;([]) : METHOD_TYPE_PARAMETER 0, null + @Lfoo/TypeAnn;([name="Simple"]) : METHOD_TYPE_PARAMETER_BOUND 0, 1, null + @Lorg/jetbrains/annotations/NotNull;([]) // invisible, parameter 0 + @Lorg/jetbrains/annotations/Nullable;([]) // invisible, parameter 1 +} + +public abstract interface foo/Simple : java/lang/Object { + +} + +public abstract interface foo/TypeAnn : java/lang/Object, java/lang/annotation/Annotation { + public abstract java.lang.String name() +} + +public abstract interface foo/TypeParameterAnn : java/lang/Object, java/lang/annotation/Annotation { + +} diff --git a/compiler/testData/codegen/asmLike/typeAnnotations/typeParameter.kt b/compiler/testData/codegen/asmLike/typeAnnotations/typeParameter.kt new file mode 100644 index 00000000000..91130363833 --- /dev/null +++ b/compiler/testData/codegen/asmLike/typeAnnotations/typeParameter.kt @@ -0,0 +1,17 @@ +// IGNORE_BACKEND: JVM +// RENDER_ANNOTATIONS +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.8 +package foo + +@Target(AnnotationTarget.TYPE_PARAMETER) +annotation class TypeParameterAnn(val name: String) + +class Kotlin { + + fun <@TypeParameterAnn("T") T> bar(p: T): T { + return p + } + +} + diff --git a/compiler/testData/codegen/asmLike/typeAnnotations/typeParameter.txt b/compiler/testData/codegen/asmLike/typeAnnotations/typeParameter.txt new file mode 100644 index 00000000000..7dfc48e0ac0 --- /dev/null +++ b/compiler/testData/codegen/asmLike/typeAnnotations/typeParameter.txt @@ -0,0 +1,11 @@ +public final class foo/Kotlin : java/lang/Object { + public void () + + (TT;)TT; + public final java.lang.Object bar(java.lang.Object p) + @Lfoo/TypeParameterAnn;([name="T"]) : METHOD_TYPE_PARAMETER 0, null +} + +public abstract interface foo/TypeParameterAnn : java/lang/Object, java/lang/annotation/Annotation { + public abstract java.lang.String name() +} diff --git a/compiler/testData/codegen/asmLike/typeAnnotations/typeParameter16.kt b/compiler/testData/codegen/asmLike/typeAnnotations/typeParameter16.kt new file mode 100644 index 00000000000..2c3939ab0fa --- /dev/null +++ b/compiler/testData/codegen/asmLike/typeAnnotations/typeParameter16.kt @@ -0,0 +1,15 @@ +// RENDER_ANNOTATIONS +// TARGET_BACKEND: JVM +// JVM_TARGET: 1.6 +package foo + +@Target(AnnotationTarget.TYPE_PARAMETER) +annotation class TypeParameterAnn(val name: String) + +class Kotlin { + + fun <@TypeParameterAnn("T") T> bar(p: T): T { + return p + } + +} diff --git a/compiler/testData/codegen/asmLike/typeAnnotations/typeParameter16.txt b/compiler/testData/codegen/asmLike/typeAnnotations/typeParameter16.txt new file mode 100644 index 00000000000..18840d0b35d --- /dev/null +++ b/compiler/testData/codegen/asmLike/typeAnnotations/typeParameter16.txt @@ -0,0 +1,10 @@ +public final class foo/Kotlin : java/lang/Object { + public void () + + (TT;)TT; + public final java.lang.Object bar(java.lang.Object p) +} + +public abstract interface foo/TypeParameterAnn : java/lang/Object, java/lang/annotation/Annotation { + public abstract java.lang.String name() +} diff --git a/compiler/testData/codegen/box/annotations/typeAnnotations/functionTypeParameterBound.kt b/compiler/testData/codegen/box/annotations/typeAnnotations/functionTypeParameterBound.kt new file mode 100644 index 00000000000..f2cf80986c7 --- /dev/null +++ b/compiler/testData/codegen/box/annotations/typeAnnotations/functionTypeParameterBound.kt @@ -0,0 +1,46 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// EMIT_JVM_TYPE_ANNOTATIONS +// JVM_TARGET: 1.8 +// WITH_REFLECT +// FULL_JDK +package foo + +import kotlin.reflect.KClass +import kotlin.reflect.full.functions + +@Target(AnnotationTarget.TYPE) +annotation class TypeAnn(val name: String) + +interface SimpleInterface +open class SimpleClass + +class Kotlin { + + fun interfaceClassBound() where T : @TypeAnn("Interface") SimpleInterface, T : @TypeAnn("Class") SimpleClass { + + } + + fun classInterfaceBound() where T : @TypeAnn("Class") SimpleClass, T : @TypeAnn("Interface") SimpleInterface { + + } +} + +fun box() : String { + val interfaceBounds = Kotlin::class.functions.single { it.name == "interfaceClassBound" }.typeParameters.single() + if (interfaceBounds.upperBounds[0].annotations.joinToString() != "@foo.TypeAnn(name=Interface)") return "fail 1: ${interfaceBounds.upperBounds[0].annotations.joinToString()}" + if ((interfaceBounds.upperBounds[0].classifier as KClass<*>).simpleName != "SimpleInterface") return "fail 1.1: ${interfaceBounds.upperBounds[0].classifier}" + + if (interfaceBounds.upperBounds[1].annotations.joinToString() != "@foo.TypeAnn(name=Class)") return "fail 2: ${interfaceBounds.upperBounds[1].annotations.joinToString()}" + if ((interfaceBounds.upperBounds[1].classifier as KClass<*>).simpleName != "SimpleClass") return "fail 2.1: ${interfaceBounds.upperBounds[1].classifier}" + + val classBounds = Kotlin::class.functions.single { it.name == "classInterfaceBound" }.typeParameters.single() + if (classBounds.upperBounds[0].annotations.joinToString() != "@foo.TypeAnn(name=Class)") return "fail 3: ${classBounds.upperBounds[0].annotations.joinToString()}" + if ((classBounds.upperBounds[0].classifier as KClass<*>).simpleName != "SimpleClass") return "fail 3.1: ${classBounds.upperBounds[0].classifier}" + + if (classBounds.upperBounds[1].annotations.joinToString() != "@foo.TypeAnn(name=Interface)") return "fail 4: ${classBounds.upperBounds[1].annotations.joinToString()}" + if ((classBounds.upperBounds[1].classifier as KClass<*>).simpleName != "SimpleInterface") return "fail 4.1: ${classBounds.upperBounds[1].classifier}" + + return "OK" +} + diff --git a/compiler/testData/codegen/box/annotations/typeAnnotations/methodTypeParameters.kt b/compiler/testData/codegen/box/annotations/typeAnnotations/methodTypeParameters.kt new file mode 100644 index 00000000000..1de17e4272e --- /dev/null +++ b/compiler/testData/codegen/box/annotations/typeAnnotations/methodTypeParameters.kt @@ -0,0 +1,183 @@ +// IGNORE_BACKEND: JVM +// IGNORE_LIGHT_ANALYSIS +// IGNORE_BACKEND_FIR: JVM_IR +// TARGET_BACKEND: JVM +// EMIT_JVM_TYPE_ANNOTATIONS +// JVM_TARGET: 1.8 +// WITH_REFLECT +// FULL_JDK +package foo + +import java.lang.reflect.AnnotatedType +import java.lang.reflect.TypeVariable +import java.lang.reflect.AnnotatedParameterizedType +import kotlin.reflect.jvm.javaMethod +import kotlin.test.fail + +@Target(AnnotationTarget.TYPE) +annotation class TypeAnn(val name: String) + +@Target(AnnotationTarget.TYPE_PARAMETER) +annotation class TypeParameterAnn + +@Target(AnnotationTarget.TYPE_PARAMETER) +@Retention(AnnotationRetention.BINARY) +annotation class TypeParameterAnnBinary + +interface Simple +class SimpleClass +interface Generic +class GenericClass + +class Kotlin { + + fun <@TypeParameterAnn @TypeParameterAnnBinary T> foo(s: T) : T { + return s; + } + + fun <@TypeParameterAnn T : @TypeAnn("Simple") Simple> interfaceBound(s: T) : T { + return s; + } + + fun <@TypeParameterAnn T : @TypeAnn("Simple") SimpleClass> classBound(s: T) : T { + return s; + } + + fun > interfaceBoundGeneric(s: T) : T { + return s; + } + + fun > classBoundGeneric(s: T) : T { + return s; + } + + fun typeParameterTypeParameterBound(s: T) : T { + return s; + } +} + +fun box(): String { + + //foo + checkTypeParameterAnnotation( + Kotlin::class.java.methods.single{it.name == "foo"}.typeParameters.single(), + "T", + "@foo.TypeParameterAnn()", + "foo" + ) + + //interfaceBound + val interfaceBound = Kotlin::class.java.methods.single { it.name == "interfaceBound" } + checkTypeParameterAnnotation( + interfaceBound.typeParameters.single(), + "T", + "@foo.TypeParameterAnn()", + "interfaceBound type parameter" + ) + + checkTypeAnnotation( + interfaceBound.typeParameters.single().annotatedBounds.single(), + "interface foo.Simple", + "@foo.TypeAnn(name=Simple)", + "interfaceBound bound" + ) + + //classBound + val classBound = Kotlin::class.java.methods.single { it.name == "classBound" } + checkTypeParameterAnnotation( + classBound.typeParameters.single(), + "T", + "@foo.TypeParameterAnn()", + "classBound type parameter" + ) + + checkTypeAnnotation( + classBound.typeParameters.single().annotatedBounds.single(), + "class foo.SimpleClass", + "@foo.TypeAnn(name=Simple)", + "classBound bound" + ) + + + //interfaceBoundGeneric + val interfaceBoundGeneric = Kotlin::class.java.methods.single { it.name == "interfaceBoundGeneric" } + checkTypeAnnotation( + interfaceBoundGeneric.typeParameters.single().annotatedBounds.single(), + "foo.Generic", + "@foo.TypeAnn(name=Generic)", + "interfaceBoundGeneric bound" + ) + + checkTypeAnnotation( + (interfaceBoundGeneric.typeParameters.single().annotatedBounds.single() as AnnotatedParameterizedType).getAnnotatedActualTypeArguments().single(), + "interface foo.Simple", + "@foo.TypeAnn(name=Simple)", + "interfaceBoundGeneric bound parameter" + ) + + //classBoundGeneric + val classBoundGeneric = Kotlin::class.java.methods.single { it.name == "classBoundGeneric" } + // Works on JDK 15 +// checkTypeAnnotation( +// classBoundGeneric.typeParameters.single().annotatedBounds.single(), +// "foo.GenericClass", +// "@foo.TypeAnn(name=GenericClass)", +// "classBoundGeneric bound" +// ) + + checkTypeAnnotation( + (classBoundGeneric.typeParameters.single().annotatedBounds.single() as AnnotatedParameterizedType).getAnnotatedActualTypeArguments().single(), + "class foo.SimpleClass", + "@foo.TypeAnn(name=SimpleClass)", + "classBoundGeneric bound parameter" + ) + + //typeParameterTypeParameterBound + val typeParameterTypeParameterBound = Kotlin::class.java.methods.single { it.name == "typeParameterTypeParameterBound" } + checkTypeParameterAnnotation( + typeParameterTypeParameterBound.typeParameters[1]!!, + "T", + "@foo.TypeParameterAnn()", + "typeParameterTypeParameterBound type parameter" + ) + // Works on JDK 15 +// checkTypeAnnotation( +// typeParameterTypeParameterBound.typeParameters[1]!!.annotatedBounds.single(), +// "Y", +// "@foo.TypeAnn(name=Y as Bound)", +// "typeParameterTypeParameterBound bound" +// ) + + return "OK" +} + +fun checkTypeParameterAnnotation( + typeParameter: TypeVariable<*>, + type: String, + annotations: String, + message: String +) { + if (typeParameter.annotation() != annotations) fail("check $message (1): ${typeParameter.annotation()} != $annotations") + + if (typeParameter.toString() != type) fail("check $message (2): ${typeParameter.toString()} != $type") +} + + +fun checkTypeAnnotation( + annotatedType: AnnotatedType, + type: String, + annotations: String, + message: String +) { + if (annotatedType.annotation() != annotations && + //JDK11+ + annotatedType . annotation () != annotations.replace("=", "=\"").replace(")", "\")") + ) fail("check $message (1): ${annotatedType.annotation()} != $annotations") + + if (annotatedType.type.toString() != type) fail("check $message (2): ${annotatedType.type} != $type") +} + + +fun AnnotatedType.annotation() = annotations.joinToString() + +fun TypeVariable<*>.annotation() = annotations.joinToString() diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 18938071c74..eca2f60b625 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -429,6 +429,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/annotations/typeAnnotations/checkingNotincorporatedInputTypes.kt"); } + @Test + @TestMetadata("functionTypeParameterBound.kt") + public void testFunctionTypeParameterBound() throws Exception { + runTest("compiler/testData/codegen/box/annotations/typeAnnotations/functionTypeParameterBound.kt"); + } + @Test @TestMetadata("implicitReturn.kt") public void testImplicitReturn() throws Exception { @@ -453,6 +459,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/annotations/typeAnnotations/methodParameters.kt"); } + @Test + @TestMetadata("methodTypeParameters.kt") + public void testMethodTypeParameters() throws Exception { + runTest("compiler/testData/codegen/box/annotations/typeAnnotations/methodTypeParameters.kt"); + } + @Test @TestMetadata("typeAnnotationTarget6.kt") public void testTypeAnnotationTarget6() throws Exception { 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 79eb6a400ce..176b38aa82e 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 @@ -429,6 +429,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/annotations/typeAnnotations/checkingNotincorporatedInputTypes.kt"); } + @Test + @TestMetadata("functionTypeParameterBound.kt") + public void testFunctionTypeParameterBound() throws Exception { + runTest("compiler/testData/codegen/box/annotations/typeAnnotations/functionTypeParameterBound.kt"); + } + @Test @TestMetadata("implicitReturn.kt") public void testImplicitReturn() throws Exception { @@ -453,6 +459,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/annotations/typeAnnotations/methodParameters.kt"); } + @Test + @TestMetadata("methodTypeParameters.kt") + public void testMethodTypeParameters() throws Exception { + runTest("compiler/testData/codegen/box/annotations/typeAnnotations/methodTypeParameters.kt"); + } + @Test @TestMetadata("typeAnnotationTarget6.kt") public void testTypeAnnotationTarget6() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/AsmLikeInstructionListingTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/AsmLikeInstructionListingTestGenerated.java index c0da01901ea..eba2cb624f6 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/AsmLikeInstructionListingTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/AsmLikeInstructionListingTestGenerated.java @@ -130,6 +130,11 @@ public class AsmLikeInstructionListingTestGenerated extends AbstractAsmLikeInstr runTest("compiler/testData/codegen/asmLike/typeAnnotations/defaultArgs.kt"); } + @TestMetadata("dontEmit.kt") + public void testDontEmit() throws Exception { + runTest("compiler/testData/codegen/asmLike/typeAnnotations/dontEmit.kt"); + } + @TestMetadata("enumClassConstructor.kt") public void testEnumClassConstructor() throws Exception { runTest("compiler/testData/codegen/asmLike/typeAnnotations/enumClassConstructor.kt"); @@ -145,6 +150,11 @@ public class AsmLikeInstructionListingTestGenerated extends AbstractAsmLikeInstr runTest("compiler/testData/codegen/asmLike/typeAnnotations/extension.kt"); } + @TestMetadata("functionTypeParameter.kt") + public void testFunctionTypeParameter() throws Exception { + runTest("compiler/testData/codegen/asmLike/typeAnnotations/functionTypeParameter.kt"); + } + @TestMetadata("implicit.kt") public void testImplicit() throws Exception { runTest("compiler/testData/codegen/asmLike/typeAnnotations/implicit.kt"); @@ -180,6 +190,11 @@ public class AsmLikeInstructionListingTestGenerated extends AbstractAsmLikeInstr runTest("compiler/testData/codegen/asmLike/typeAnnotations/property.kt"); } + @TestMetadata("propertyTypeParameter.kt") + public void testPropertyTypeParameter() throws Exception { + runTest("compiler/testData/codegen/asmLike/typeAnnotations/propertyTypeParameter.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/codegen/asmLike/typeAnnotations/simple.kt"); @@ -199,5 +214,15 @@ public class AsmLikeInstructionListingTestGenerated extends AbstractAsmLikeInstr public void testSyntheticAccessors() throws Exception { runTest("compiler/testData/codegen/asmLike/typeAnnotations/syntheticAccessors.kt"); } + + @TestMetadata("typeParameter.kt") + public void testTypeParameter() throws Exception { + runTest("compiler/testData/codegen/asmLike/typeAnnotations/typeParameter.kt"); + } + + @TestMetadata("typeParameter16.kt") + public void testTypeParameter16() throws Exception { + runTest("compiler/testData/codegen/asmLike/typeAnnotations/typeParameter16.kt"); + } } } diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 940d1401cc6..2b08721b7ea 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -372,6 +372,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class TypeAnnotations extends AbstractLightAnalysisModeTest { + @TestMetadata("methodTypeParameters.kt") + public void ignoreMethodTypeParameters() throws Exception { + runTest("compiler/testData/codegen/box/annotations/typeAnnotations/methodTypeParameters.kt"); + } + private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); } @@ -385,6 +390,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/annotations/typeAnnotations/checkingNotincorporatedInputTypes.kt"); } + @TestMetadata("functionTypeParameterBound.kt") + public void testFunctionTypeParameterBound() throws Exception { + runTest("compiler/testData/codegen/box/annotations/typeAnnotations/functionTypeParameterBound.kt"); + } + @TestMetadata("implicitReturn.kt") public void testImplicitReturn() throws Exception { runTest("compiler/testData/codegen/box/annotations/typeAnnotations/implicitReturn.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrAsmLikeInstructionListingTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrAsmLikeInstructionListingTestGenerated.java index 4ad345be618..bb2da73a0bb 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrAsmLikeInstructionListingTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/ir/IrAsmLikeInstructionListingTestGenerated.java @@ -130,6 +130,11 @@ public class IrAsmLikeInstructionListingTestGenerated extends AbstractIrAsmLikeI runTest("compiler/testData/codegen/asmLike/typeAnnotations/defaultArgs.kt"); } + @TestMetadata("dontEmit.kt") + public void testDontEmit() throws Exception { + runTest("compiler/testData/codegen/asmLike/typeAnnotations/dontEmit.kt"); + } + @TestMetadata("enumClassConstructor.kt") public void testEnumClassConstructor() throws Exception { runTest("compiler/testData/codegen/asmLike/typeAnnotations/enumClassConstructor.kt"); @@ -145,6 +150,11 @@ public class IrAsmLikeInstructionListingTestGenerated extends AbstractIrAsmLikeI runTest("compiler/testData/codegen/asmLike/typeAnnotations/extension.kt"); } + @TestMetadata("functionTypeParameter.kt") + public void testFunctionTypeParameter() throws Exception { + runTest("compiler/testData/codegen/asmLike/typeAnnotations/functionTypeParameter.kt"); + } + @TestMetadata("implicit.kt") public void testImplicit() throws Exception { runTest("compiler/testData/codegen/asmLike/typeAnnotations/implicit.kt"); @@ -180,6 +190,11 @@ public class IrAsmLikeInstructionListingTestGenerated extends AbstractIrAsmLikeI runTest("compiler/testData/codegen/asmLike/typeAnnotations/property.kt"); } + @TestMetadata("propertyTypeParameter.kt") + public void testPropertyTypeParameter() throws Exception { + runTest("compiler/testData/codegen/asmLike/typeAnnotations/propertyTypeParameter.kt"); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { runTest("compiler/testData/codegen/asmLike/typeAnnotations/simple.kt"); @@ -199,5 +214,15 @@ public class IrAsmLikeInstructionListingTestGenerated extends AbstractIrAsmLikeI public void testSyntheticAccessors() throws Exception { runTest("compiler/testData/codegen/asmLike/typeAnnotations/syntheticAccessors.kt"); } + + @TestMetadata("typeParameter.kt") + public void testTypeParameter() throws Exception { + runTest("compiler/testData/codegen/asmLike/typeAnnotations/typeParameter.kt"); + } + + @TestMetadata("typeParameter16.kt") + public void testTypeParameter16() throws Exception { + runTest("compiler/testData/codegen/asmLike/typeAnnotations/typeParameter16.kt"); + } } }