Support type annotations

#KT-35843 Fixed
This commit is contained in:
Mikhael Bogdanov
2019-12-30 09:12:28 +01:00
parent fde9b21a40
commit 2ed0cb2a89
52 changed files with 1728 additions and 10 deletions
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.config.JVMConfigurationKeys;
import org.jetbrains.kotlin.config.JvmTarget;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.*;
@@ -627,4 +628,38 @@ public abstract class AnnotationCodegen {
private static AnnotationVisitor safe(@Nullable AnnotationVisitor av) {
return av == null ? NO_ANNOTATION_VISITOR : av;
}
public static void writeTypeAnnotations(
@NotNull MethodVisitor mv,
@NotNull GenerationState state,
int parameterIndex,
@Nullable KotlinType type,
@NotNull InnerClassConsumer innerClassConsumer
) {
if (type == null ||
state.getTarget() == JvmTarget.JVM_1_6 ||
!state.getConfiguration().getBoolean(JVMConfigurationKeys.EMIT_JVM_TYPE_ANNOTATIONS)) {
return;
}
Iterable<TypePathInfo> infos =
new TypeAnnotationCollector().collectTypeAnnotations(type, TypeReference.METHOD_FORMAL_PARAMETER);
for (TypePathInfo info : infos) {
for (AnnotationDescriptor annotationDescriptor : info.getAnnotations()) {
TypeReference typeReference = parameterIndex != -1 ?
TypeReference.newFormalParameterReference(parameterIndex)
: TypeReference.newTypeReference(TypeReference.METHOD_RETURN);
AnnotationCodegen codegen = new AnnotationCodegen(innerClassConsumer, state) {
@NotNull
@Override
AnnotationVisitor visitAnnotation(String descr, boolean visible) {
return safe(mv.visitTypeAnnotation(typeReference.getValue(), info.getPath(), descr, visible));
}
};
codegen.genAnnotation(annotationDescriptor);
}
}
}
}
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
import org.jetbrains.kotlin.config.JvmDefaultMode;
import org.jetbrains.kotlin.config.LanguageFeature;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotated;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature;
@@ -56,7 +55,10 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.org.objectweb.asm.*;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import org.jetbrains.org.objectweb.asm.commons.Method;
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor;
@@ -531,7 +533,7 @@ public class FunctionCodegen {
continue;
}
Annotated annotated =
ParameterDescriptor annotated =
kind == JvmMethodParameterKind.VALUE
? iterator.next()
: kind == JvmMethodParameterKind.RECEIVER
@@ -540,10 +542,15 @@ public class FunctionCodegen {
if (annotated != null) {
//noinspection ConstantConditions
AnnotationCodegen.forParameter(i - syntheticParameterCount, mv, innerClassConsumer, state)
int parameterIndex = i - syntheticParameterCount;
AnnotationCodegen.forParameter(parameterIndex, mv, innerClassConsumer, state)
.genAnnotations(annotated, parameterSignature.getAsmType());
AnnotationCodegen.writeTypeAnnotations(mv, state, parameterIndex, annotated.getType(), innerClassConsumer);
}
}
AnnotationCodegen.writeTypeAnnotations(mv, state, -1, functionDescriptor.getReturnType(), innerClassConsumer);
}
@Nullable
@@ -0,0 +1,90 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
import org.jetbrains.kotlin.types.*
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.TypePath
class TypePathInfo(
val path: TypePath?,
val annotations: List<AnnotationDescriptor>
)
private class State(val type: Int, val path: MutableList<String>) {
val results = arrayListOf<TypePathInfo>()
fun addStep(step: String) {
path.add(step)
}
fun removeStep(step: String) {
path.removeAt(path.lastIndex)
}
fun rememberAnnotations(annotations: List<AnnotationDescriptor>) {
results.add(TypePathInfo(TypePath.fromString(path.joinToString("")), annotations))
}
}
class TypeAnnotationCollector {
private lateinit var state: State
fun collectTypeAnnotations(kotlinType: KotlinType, annotationType: Int): ArrayList<TypePathInfo> {
state = State(annotationType, arrayListOf())
kotlinType.collectTypeAnnotations()
return state.results
}
private fun KotlinType.collectTypeAnnotations() {
if (isFlexible()) {
return upperIfFlexible().collectTypeAnnotations()
} else if ((this.constructor.declarationDescriptor as? ClassDescriptor)?.isInner == true) {
//skip inner classes for now it's not clear should type annotations on outer be supported or not
return
}
typeAnnotations.takeIf { it.isNotEmpty() }?.let { state.rememberAnnotations(it) }
arguments.forEachIndexed { index, type ->
//skip in/out variance for now it's not clear should type annotations on wildcard bound be supported or not
if (type.projectionKind == Variance.INVARIANT) {
when {
KotlinBuiltIns.isArray(this) -> type.type.process("[")
else -> type.type.process("$index;")
}
}
}
}
fun KotlinType.process(step: String) {
state.addStep(step)
this.collectTypeAnnotations()
state.removeStep(step)
}
private val KotlinType.typeAnnotations
get() = annotations.filter {
//We only generate annotations which have the TYPE_USE Java target.
// Those are type annotations which were compiled with JVM target bytecode version 1.8 or greater
(it.annotationClass as? DeserializedClassDescriptor)?.let { classDescriptor ->
((classDescriptor.source as? KotlinJvmBinarySourceElement)?.binaryClass as? FileBasedKotlinClass)?.classVersion ?: 0 >= Opcodes.V1_8
} ?: true
}
}
@@ -289,6 +289,12 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
)
var allowNoSourceFiles: Boolean by FreezableVar(false)
@Argument(
value = "-Xemit-jvm-type-annotations",
description = "Emit JVM type annotations in bytecode"
)
var emitJvmTypeAnnotations: Boolean by FreezableVar(false)
override fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> {
val result = super.configureAnalysisFlags(collector)
result[JvmAnalysisFlags.strictMetadataVersionSemantics] = strictMetadataVersionSemantics
@@ -152,6 +152,7 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
arguments.noExceptionOnExplicitEqualsForBoxedNull
)
put(JVMConfigurationKeys.DISABLE_OPTIMIZATION, arguments.noOptimize)
put(JVMConfigurationKeys.EMIT_JVM_TYPE_ANNOTATIONS, arguments.emitJvmTypeAnnotations)
if (!JVMConstructorCallNormalizationMode.isSupportedValue(arguments.constructorCallNormalizationMode)) {
getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(
@@ -110,4 +110,7 @@ public class JVMConfigurationKeys {
public static final CompilerConfigurationKey<Boolean> ENABLE_JVM_DEFAULT =
CompilerConfigurationKey.create("Allow to use '@JvmDefault'");
public static final CompilerConfigurationKey<Boolean> EMIT_JVM_TYPE_ANNOTATIONS =
CompilerConfigurationKey.create("Emit JVM type annotations in bytecode");
}
+1
View File
@@ -18,6 +18,7 @@ where advanced options include:
'enable' since language version 1.3
-Xdump-declarations-to=<path> Path to JSON file to dump Java to Kotlin declaration mappings
-Xdisable-standard-script Disable standard kotlin script support
-Xemit-jvm-type-annotations Emit JVM type annotations in bytecode
-Xexpression Evaluate the given string as a Kotlin script
-Xfriend-paths=<path> Paths to output directories for friend modules (whose internals should be visible)
-Xmultifile-parts-inherit Compile multifile classes as a hierarchy of parts and facade
@@ -0,0 +1,51 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
package foo
@Target(AnnotationTarget.TYPE)
annotation class Ann
@Target(AnnotationTarget.TYPE)
annotation class Ann2
@Target(AnnotationTarget.TYPE)
annotation class Ann3
@Target(AnnotationTarget.TYPE)
annotation class Ann4
class Bar<T>
class Kotlin {
fun foo(s: @Ann Bar<@Ann2 String>) {
}
fun foo(): @Ann Bar<@Ann2 String>? {
return null
}
fun fooArray(s: @Ann Array<@Ann2 Bar<@Ann3 String>>) {
}
fun fooArray(): @Ann Array<@Ann2 Bar<@Ann3 String>>? {
return null
}
fun fooArrayArray(s: @Ann Array<@Ann2 Array<@Ann3 Bar<@Ann4 String>>>) {
}
fun fooArrayArray(): @Ann Array<@Ann2 Array<@Ann3 Bar<@Ann4 String>>>? {
return null
}
fun <T> foo(s: @Ann T) {
}
fun <T> fooGeneric(s: @Ann Bar<@Ann2 T>) {
}
}
@@ -0,0 +1,60 @@
public abstract interface foo/Ann : java/lang/Object, java/lang/annotation/Annotation {
}
public abstract interface foo/Ann2 : java/lang/Object, java/lang/annotation/Annotation {
}
public abstract interface foo/Ann3 : java/lang/Object, java/lang/annotation/Annotation {
}
public abstract interface foo/Ann4 : java/lang/Object, java/lang/annotation/Annotation {
}
public final class foo/Bar : java/lang/Object {
public void <init>()
}
public final class foo/Kotlin : java/lang/Object {
public void <init>()
public final void foo(foo.Bar s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/Ann2;([]) : METHOD_FORMAL_PARAMETER 0, 0;
public final foo.Bar foo()
@Lfoo/Ann;([]) : METHOD_RETURN, null
@Lfoo/Ann2;([]) : METHOD_RETURN, 0;
public final void foo(java.lang.Object s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
public final void fooArray(foo.Bar[] s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/Ann2;([]) : METHOD_FORMAL_PARAMETER 0, [
@Lfoo/Ann3;([]) : METHOD_FORMAL_PARAMETER 0, [0;
public final foo.Bar[] fooArray()
@Lfoo/Ann;([]) : METHOD_RETURN, null
@Lfoo/Ann2;([]) : METHOD_RETURN, [
@Lfoo/Ann3;([]) : METHOD_RETURN, [0;
public final void fooArrayArray(foo.Bar[][] s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/Ann2;([]) : METHOD_FORMAL_PARAMETER 0, [
@Lfoo/Ann3;([]) : METHOD_FORMAL_PARAMETER 0, [[
@Lfoo/Ann4;([]) : METHOD_FORMAL_PARAMETER 0, [[0;
public final foo.Bar[][] fooArrayArray()
@Lfoo/Ann;([]) : METHOD_RETURN, null
@Lfoo/Ann2;([]) : METHOD_RETURN, [
@Lfoo/Ann3;([]) : METHOD_RETURN, [[
@Lfoo/Ann4;([]) : METHOD_RETURN, [[0;
public final void fooGeneric(foo.Bar s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/Ann2;([]) : METHOD_FORMAL_PARAMETER 0, 0;
}
@@ -0,0 +1,18 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
package foo
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn(val name: String)
class Kotlin(s: @TypeAnn("1") String, p: @TypeAnn("123") String) {
private constructor(s: @TypeAnn("private") String) : this("1", "2")
fun foo() {
{ Kotlin("123") }()
}
}
@@ -0,0 +1,28 @@
final class foo/Kotlin$foo$1 : kotlin/jvm/internal/Lambda, kotlin/jvm/functions/Function0 {
public final static foo.Kotlin$foo$1 INSTANCE
static void <clinit>()
void <init>()
public java.lang.Object invoke()
public final foo.Kotlin invoke()
}
public final class foo/Kotlin : java/lang/Object {
public void <init>(java.lang.String s, java.lang.String p)
@Lfoo/TypeAnn;([name="1"]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/TypeAnn;([name="123"]) : METHOD_FORMAL_PARAMETER 1, null
private void <init>(java.lang.String s)
@Lfoo/TypeAnn;([name="private"]) : METHOD_FORMAL_PARAMETER 0, null
public void <init>(java.lang.String s, kotlin.jvm.internal.DefaultConstructorMarker $constructor_marker)
public final void foo()
}
public abstract interface foo/TypeAnn : java/lang/Object, java/lang/annotation/Annotation {
public abstract java.lang.String name()
}
@@ -0,0 +1,17 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
package foo
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn(val name: String)
class Kotlin {
fun foo(s: @TypeAnn("1") String = "1", x: @TypeAnn("2") Int = 123): @TypeAnn("return") Any? {
return null
}
}
@@ -0,0 +1,14 @@
public final class foo/Kotlin : java/lang/Object {
public void <init>()
public final java.lang.Object foo(java.lang.String s, int x)
@Lfoo/TypeAnn;([name="1"]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/TypeAnn;([name="2"]) : METHOD_FORMAL_PARAMETER 1, null
@Lfoo/TypeAnn;([name="return"]) : METHOD_RETURN, null
public static java.lang.Object foo$default(foo.Kotlin p0, java.lang.String p1, int p2, int p3, java.lang.Object p4)
}
public abstract interface foo/TypeAnn : java/lang/Object, java/lang/annotation/Annotation {
public abstract java.lang.String name()
}
@@ -0,0 +1,16 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
package foo
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn
enum class Kotlin (s: @TypeAnn String) {
A("123") {
fun foo() {}
};
}
@@ -0,0 +1,26 @@
final class foo/Kotlin$A : foo/Kotlin {
void <init>(java.lang.String $enum_name_or_ordinal$0, int $enum_name_or_ordinal$1)
public final void foo()
}
public class foo/Kotlin : java/lang/Enum {
private final static foo.Kotlin[] $VALUES
public final static foo.Kotlin A
static void <clinit>()
private void <init>(java.lang.String $enum_name_or_ordinal$0, int $enum_name_or_ordinal$1, java.lang.String s)
@Lfoo/TypeAnn;([]) : METHOD_FORMAL_PARAMETER 0, null
public void <init>(java.lang.String $enum_name_or_ordinal$0, int $enum_name_or_ordinal$1, java.lang.String s, kotlin.jvm.internal.DefaultConstructorMarker $constructor_marker)
public static foo.Kotlin valueOf(java.lang.String p0)
public static foo.Kotlin[] values()
}
public abstract interface foo/TypeAnn : java/lang/Object, java/lang/annotation/Annotation {
}
@@ -0,0 +1,15 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
package foo
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn(val name: String)
class Kotlin {
fun @TypeAnn("ext") String.foo2(s: @TypeAnn("param") String) {
}
}
@@ -0,0 +1,11 @@
public final class foo/Kotlin : java/lang/Object {
public void <init>()
public final void foo2(java.lang.String $this$foo2, java.lang.String s)
@Lfoo/TypeAnn;([name="ext"]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/TypeAnn;([name="param"]) : METHOD_FORMAL_PARAMETER 1, null
}
public abstract interface foo/TypeAnn : java/lang/Object, java/lang/annotation/Annotation {
public abstract java.lang.String name()
}
@@ -0,0 +1,29 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
package foo
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn(val name: String)
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.BINARY)
annotation class TypeAnnBinary
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.SOURCE)
annotation class TypeAnnSource
class Kotlin {
fun foo2(): @TypeAnn("2") @TypeAnnBinary @TypeAnnSource String {
return "OK"
}
fun foo3() = foo2()
fun foo4() = { foo2() }()
}
@@ -0,0 +1,39 @@
final class foo/Kotlin$foo4$1 : kotlin/jvm/internal/Lambda, kotlin/jvm/functions/Function0 {
final foo.Kotlin this$0
void <init>(foo.Kotlin p0)
public java.lang.Object invoke()
public final java.lang.String invoke()
@Lfoo/TypeAnn;([name="2"]) : METHOD_RETURN, null
@Lfoo/TypeAnnBinary;([]) : METHOD_RETURN, null // invisible
}
public final class foo/Kotlin : java/lang/Object {
public void <init>()
public final java.lang.String foo2()
@Lfoo/TypeAnn;([name="2"]) : METHOD_RETURN, null
@Lfoo/TypeAnnBinary;([]) : METHOD_RETURN, null // invisible
public final java.lang.String foo3()
@Lfoo/TypeAnn;([name="2"]) : METHOD_RETURN, null
@Lfoo/TypeAnnBinary;([]) : METHOD_RETURN, null // invisible
public final java.lang.String foo4()
@Lfoo/TypeAnn;([name="2"]) : METHOD_RETURN, null
@Lfoo/TypeAnnBinary;([]) : METHOD_RETURN, null // invisible
}
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 {
}
@@ -0,0 +1,13 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
package foo
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn
class Kotlin {
inner class Inner(s: @TypeAnn String) {}
}
@@ -0,0 +1,14 @@
public final class foo/Kotlin$Inner : java/lang/Object {
final foo.Kotlin this$0
public void <init>(foo.Kotlin $outer, java.lang.String s)
@Lfoo/TypeAnn;([]) : METHOD_FORMAL_PARAMETER 0, null
}
public final class foo/Kotlin : java/lang/Object {
public void <init>()
}
public abstract interface foo/TypeAnn : java/lang/Object, java/lang/annotation/Annotation {
}
@@ -0,0 +1,17 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// WITH_RUNTIME
package foo
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn(val name: String)
class FooClass {
@JvmOverloads
fun foo(s: @TypeAnn("1") String = "1", x: @TypeAnn("2") Int = 123) : @TypeAnn("return") Any? {
return null
}
}
@@ -0,0 +1,21 @@
public final class foo/FooClass : java/lang/Object {
public void <init>()
public final java.lang.Object foo(java.lang.String s, int x)
@Lfoo/TypeAnn;([name="1"]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/TypeAnn;([name="2"]) : METHOD_FORMAL_PARAMETER 1, null
@Lfoo/TypeAnn;([name="return"]) : METHOD_RETURN, null
public final java.lang.Object foo(java.lang.String s)
@Lfoo/TypeAnn;([name="1"]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/TypeAnn;([name="return"]) : METHOD_RETURN, null
public final java.lang.Object foo()
@Lfoo/TypeAnn;([name="return"]) : METHOD_RETURN, null
public static java.lang.Object foo$default(foo.FooClass p0, java.lang.String p1, int p2, int p3, java.lang.Object p4)
}
public abstract interface foo/TypeAnn : java/lang/Object, java/lang/annotation/Annotation {
public abstract java.lang.String name()
}
@@ -0,0 +1,28 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// WITH_RUNTIME
package foo
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn(val name: String)
class FooClass {
companion object {
@JvmStatic
fun foo(s: @TypeAnn("1") String, x: @TypeAnn("2") Int): @TypeAnn("return") Any? {
return null
}
}
}
object Foo {
@JvmStatic
fun foo(s: @TypeAnn("1") String , x: @TypeAnn("2") Int): @TypeAnn("return") Any? {
return null
}
}
@@ -0,0 +1,40 @@
public final class foo/Foo : java/lang/Object {
public final static foo.Foo INSTANCE
static void <clinit>()
private void <init>()
public final static java.lang.Object foo(java.lang.String s, int x)
@Lfoo/TypeAnn;([name="1"]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/TypeAnn;([name="2"]) : METHOD_FORMAL_PARAMETER 1, null
@Lfoo/TypeAnn;([name="return"]) : METHOD_RETURN, null
}
public final class foo/FooClass$Companion : java/lang/Object {
private void <init>()
public void <init>(kotlin.jvm.internal.DefaultConstructorMarker $constructor_marker)
public final java.lang.Object foo(java.lang.String s, int x)
@Lfoo/TypeAnn;([name="1"]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/TypeAnn;([name="2"]) : METHOD_FORMAL_PARAMETER 1, null
@Lfoo/TypeAnn;([name="return"]) : METHOD_RETURN, null
}
public final class foo/FooClass : java/lang/Object {
public final static foo.FooClass$Companion Companion
static void <clinit>()
public void <init>()
public final static java.lang.Object foo(java.lang.String s, int x)
@Lfoo/TypeAnn;([name="1"]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/TypeAnn;([name="2"]) : METHOD_FORMAL_PARAMETER 1, null
@Lfoo/TypeAnn;([name="return"]) : METHOD_RETURN, null
}
public abstract interface foo/TypeAnn : java/lang/Object, java/lang/annotation/Annotation {
public abstract java.lang.String name()
}
@@ -0,0 +1,57 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
package foo
@Target(AnnotationTarget.TYPE)
annotation class Ann
@Target(AnnotationTarget.TYPE)
annotation class Ann2
@Target(AnnotationTarget.TYPE)
annotation class Ann3
@Target(AnnotationTarget.TYPE)
annotation class Ann4
class Bar<T>
class Outer {
inner class Inner<T>
}
class Kotlin {
fun foo(s: @Ann Outer.Inner<@Ann2 String>) {
}
fun foo(): @Ann Outer.Inner<@Ann2 String>? {
return null
}
fun fooArray(s: @Ann Array<@Ann2 Outer.Inner<@Ann3 String>>) {
}
fun fooArray(): @Ann Array<@Ann2 Outer.Inner<@Ann3 String>>? {
return null
}
fun fooArrayIn(s: @Ann Array<in @Ann2 Outer.Inner<@Ann3 String>>) {
}
fun fooArrayOut(): @Ann Array<out @Ann2 Outer.Inner<@Ann3 String>>? {
return null
}
fun <T> fooGenericIn(s: @Ann Bar<in @Ann2 T>) {
}
fun <T> fooGenericOut(s: @Ann Bar<out @Ann2 T>) {
}
}
@@ -0,0 +1,55 @@
public abstract interface foo/Ann : java/lang/Object, java/lang/annotation/Annotation {
}
public abstract interface foo/Ann2 : java/lang/Object, java/lang/annotation/Annotation {
}
public abstract interface foo/Ann3 : java/lang/Object, java/lang/annotation/Annotation {
}
public abstract interface foo/Ann4 : java/lang/Object, java/lang/annotation/Annotation {
}
public final class foo/Bar : java/lang/Object {
public void <init>()
}
public final class foo/Kotlin : java/lang/Object {
public void <init>()
public final void foo(foo.Outer$Inner s)
public final foo.Outer$Inner foo()
public final void fooArray(foo.Outer$Inner[] s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
public final foo.Outer$Inner[] fooArray()
@Lfoo/Ann;([]) : METHOD_RETURN, null
public final void fooArrayIn(java.lang.Object[] s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
public final foo.Outer$Inner[] fooArrayOut()
@Lfoo/Ann;([]) : METHOD_RETURN, null
public final void fooGenericIn(foo.Bar s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
public final void fooGenericOut(foo.Bar s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
}
public final class foo/Outer$Inner : java/lang/Object {
final foo.Outer this$0
public void <init>(foo.Outer $outer)
}
public final class foo/Outer : java/lang/Object {
public void <init>()
}
@@ -0,0 +1,43 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
// WITH_RUNTIME
// WITH_REFLECT
// FULL_JDK
package foo
import java.lang.reflect.AnnotatedType
import kotlin.reflect.jvm.javaMethod
import kotlin.test.fail
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn(val name: String)
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.BINARY)
annotation class TypeAnnBinary
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.SOURCE)
annotation class TypeAnnSource
class Kotlin {
val valProp: @TypeAnn("1") @TypeAnnBinary @TypeAnnSource String = "123"
var varProp: @TypeAnn("1") @TypeAnnBinary @TypeAnnSource String = "123"
var customSetter: @TypeAnn("1") @TypeAnnBinary @TypeAnnSource String = "123"
set(field: String) {}
@JvmField
var jvmField: @TypeAnn("1") @TypeAnnBinary @TypeAnnSource String = "123"
lateinit var lateinitProp: @TypeAnn("1") @TypeAnnBinary @TypeAnnSource String
companion object {
var companionVarProperty: @TypeAnn("1") @TypeAnnBinary @TypeAnnSource String = "123"
}
}
@@ -0,0 +1,39 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
package foo
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn(val name: String)
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.BINARY)
annotation class TypeAnnBinary
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.SOURCE)
annotation class TypeAnnSource
class Kotlin {
private fun foo(s: @TypeAnn("1") @TypeAnnBinary @TypeAnnSource String) {
}
fun foo2(): @TypeAnn("2") @TypeAnnBinary @TypeAnnSource String {
return "OK"
}
fun fooArray(s: Array<@TypeAnn("3") @TypeAnnBinary @TypeAnnSource String>) {
}
fun fooArray2(): Array<@TypeAnn("4") @TypeAnnBinary @TypeAnnSource String>? {
{
foo2()
foo("123")
}()
return null
}
}
@@ -0,0 +1,43 @@
final class foo/Kotlin$fooArray2$1 : kotlin/jvm/internal/Lambda, kotlin/jvm/functions/Function0 {
final foo.Kotlin this$0
void <init>(foo.Kotlin p0)
public java.lang.Object invoke()
public final void invoke()
}
public final class foo/Kotlin : java/lang/Object {
public void <init>()
public final static void access$foo(foo.Kotlin $this, java.lang.String s)
private final void foo(java.lang.String s)
@Lfoo/TypeAnn;([name="1"]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/TypeAnnBinary;([]) : METHOD_FORMAL_PARAMETER 0, null // invisible
public final java.lang.String foo2()
@Lfoo/TypeAnn;([name="2"]) : METHOD_RETURN, null
@Lfoo/TypeAnnBinary;([]) : METHOD_RETURN, null // invisible
public final void fooArray(java.lang.String[] s)
@Lfoo/TypeAnn;([name="3"]) : METHOD_FORMAL_PARAMETER 0, [
@Lfoo/TypeAnnBinary;([]) : METHOD_FORMAL_PARAMETER 0, [ // invisible
public final java.lang.String[] fooArray2()
@Lfoo/TypeAnn;([name="4"]) : METHOD_RETURN, [
@Lfoo/TypeAnnBinary;([]) : METHOD_RETURN, [ // invisible
}
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 {
}
@@ -0,0 +1,20 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
package foo
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn(val name: String)
class Kotlin {
fun foo(s: @TypeAnn("1") String, x: @TypeAnn("2") Int) {
}
fun fooArray(s: Array<@TypeAnn("3") String>, i: Array<@TypeAnn("3") Int>) {
}
}
@@ -0,0 +1,15 @@
public final class foo/Kotlin : java/lang/Object {
public void <init>()
public final void foo(java.lang.String s, int x)
@Lfoo/TypeAnn;([name="1"]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/TypeAnn;([name="2"]) : METHOD_FORMAL_PARAMETER 1, null
public final void fooArray(java.lang.String[] s, java.lang.Integer[] i)
@Lfoo/TypeAnn;([name="3"]) : METHOD_FORMAL_PARAMETER 0, [
@Lfoo/TypeAnn;([name="3"]) : METHOD_FORMAL_PARAMETER 1, [
}
public abstract interface foo/TypeAnn : java/lang/Object, java/lang/annotation/Annotation {
public abstract java.lang.String name()
}
@@ -0,0 +1,57 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TYPE_ANNOTATIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// JVM_TARGET: 1.8
package foo
@Target(AnnotationTarget.TYPE)
annotation class Ann
@Target(AnnotationTarget.TYPE)
annotation class Ann2
@Target(AnnotationTarget.TYPE)
annotation class Ann3
@Target(AnnotationTarget.TYPE)
annotation class Ann4
class Bar<T>
class Outer {
class NestedStatic<T>
}
class Kotlin {
fun foo(s: @Ann Outer.NestedStatic<@Ann2 String>) {
}
fun foo(): @Ann Outer.NestedStatic<@Ann2 String>? {
return null
}
fun fooArray(s: @Ann Array<@Ann2 Outer.NestedStatic<@Ann3 String>>) {
}
fun fooArray(): @Ann Array<@Ann2 Outer.NestedStatic<@Ann3 String>>? {
return null
}
fun fooArrayIn(s: @Ann Array<in @Ann2 Outer.NestedStatic<@Ann3 String>>) {
}
fun fooArrayOut(): @Ann Array<out @Ann2 Outer.NestedStatic<@Ann3 String>>? {
return null
}
fun <T> fooGenericIn(s: @Ann Bar<in @Ann2 T>) {
}
fun <T> fooGenericOut(s: @Ann Bar<out @Ann2 T>) {
}
}
@@ -0,0 +1,61 @@
public abstract interface foo/Ann : java/lang/Object, java/lang/annotation/Annotation {
}
public abstract interface foo/Ann2 : java/lang/Object, java/lang/annotation/Annotation {
}
public abstract interface foo/Ann3 : java/lang/Object, java/lang/annotation/Annotation {
}
public abstract interface foo/Ann4 : java/lang/Object, java/lang/annotation/Annotation {
}
public final class foo/Bar : java/lang/Object {
public void <init>()
}
public final class foo/Kotlin : java/lang/Object {
public void <init>()
public final void foo(foo.Outer$NestedStatic s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/Ann2;([]) : METHOD_FORMAL_PARAMETER 0, 0;
public final foo.Outer$NestedStatic foo()
@Lfoo/Ann;([]) : METHOD_RETURN, null
@Lfoo/Ann2;([]) : METHOD_RETURN, 0;
public final void fooArray(foo.Outer$NestedStatic[] s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
@Lfoo/Ann2;([]) : METHOD_FORMAL_PARAMETER 0, [
@Lfoo/Ann3;([]) : METHOD_FORMAL_PARAMETER 0, [0;
public final foo.Outer$NestedStatic[] fooArray()
@Lfoo/Ann;([]) : METHOD_RETURN, null
@Lfoo/Ann2;([]) : METHOD_RETURN, [
@Lfoo/Ann3;([]) : METHOD_RETURN, [0;
public final void fooArrayIn(java.lang.Object[] s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
public final foo.Outer$NestedStatic[] fooArrayOut()
@Lfoo/Ann;([]) : METHOD_RETURN, null
public final void fooGenericIn(foo.Bar s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
public final void fooGenericOut(foo.Bar s)
@Lfoo/Ann;([]) : METHOD_FORMAL_PARAMETER 0, null
}
public final class foo/Outer$NestedStatic : java/lang/Object {
public void <init>()
}
public final class foo/Outer : java/lang/Object {
public void <init>()
}
@@ -0,0 +1,76 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
// JVM_TARGET: 1.8
// WITH_REFLECT
// FULL_JDK
// FILE: ImplicitReturn.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class ImplicitReturn {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
public @ interface TypeAnn {}
@ImplicitReturn.TypeAnn
public String bar() {
return "OK";
}
}
// FILE: Kotlin.kt
import java.lang.reflect.AnnotatedType
import kotlin.reflect.jvm.javaMethod
import kotlin.reflect.jvm.javaField
import kotlin.test.fail
class Kotlin {
fun foo() = ImplicitReturn().bar()
@JvmField
val field = ImplicitReturn().bar()
}
fun box(): String {
checkTypeAnnotation(
Kotlin::foo.javaMethod!!.annotatedReturnType,
"class java.lang.String",
"@ImplicitReturn\$TypeAnn()",
"foo"
)
checkTypeAnnotation(
Kotlin::field.javaField!!.annotatedType,
"class java.lang.String",
"@ImplicitReturn\$TypeAnn()",
"foo"
)
return Kotlin().foo()
}
fun checkTypeAnnotation(
annotatedType: AnnotatedType,
type: String,
annotations: String,
message: String
) {
if (annotatedType.annotation() != annotations) fail("check $message (1): ${annotatedType.annotation()} != $annotations")
if (annotatedType.type.toString() != type) fail("check $message (2): ${annotatedType.type} != $type")
}
fun AnnotatedType.annotation() = annotations.joinToString()
@@ -0,0 +1,57 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
// JVM_TARGET: 1.8
// WITH_REFLECT
// FULL_JDK
package foo
import java.lang.reflect.AnnotatedType
import kotlin.reflect.jvm.javaMethod
import kotlin.test.fail
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn
@Target(AnnotationTarget.TYPE)
@Retention(AnnotationRetention.BINARY)
annotation class TypeAnnBinary
class Kotlin {
fun foo(s: @TypeAnn @TypeAnnBinary String) {
}
fun foo2(): @TypeAnn @TypeAnnBinary String {
return "OK"
}
}
fun box(): String {
checkTypeAnnotation(
Kotlin::foo.javaMethod!!.annotatedParameterTypes.single(),
"class java.lang.String",
"@foo.TypeAnn()",
"foo"
)
checkTypeAnnotation(Kotlin::foo2.javaMethod!!.annotatedReturnType, "class java.lang.String", "@foo.TypeAnn()", "foo2")
return "OK"
}
fun checkTypeAnnotation(
annotatedType: AnnotatedType,
type: String,
annotations: String,
message: String
) {
if (annotatedType.annotation() != annotations) fail("check $message (1): ${annotatedType.annotation()} != $annotations")
if (annotatedType.type.toString() != type) fail("check $message (2): ${annotatedType.type} != $type")
}
fun AnnotatedType.annotation() = annotations.joinToString()
@@ -0,0 +1,65 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
// JVM_TARGET: 1.8
// WITH_REFLECT
// FULL_JDK
// FILE: foo/TypeAnn.java
package foo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
public @interface TypeAnn {}
// FILE: test.kt
package foo
import java.lang.reflect.AnnotatedType
import kotlin.reflect.jvm.javaMethod
import kotlin.test.fail
class Kotlin {
fun foo(s: @TypeAnn String) {
}
fun foo2(): @TypeAnn String {
return "OK"
}
}
fun box(): String {
checkTypeAnnotation(
Kotlin::foo.javaMethod!!.annotatedParameterTypes.single(),
"class java.lang.String",
"@foo.TypeAnn()",
"foo"
)
checkTypeAnnotation(Kotlin::foo2.javaMethod!!.annotatedReturnType, "class java.lang.String", "@foo.TypeAnn()", "foo2")
return "OK"
}
fun checkTypeAnnotation(
annotatedType: AnnotatedType,
type: String,
annotations: String,
message: String
) {
if (annotatedType.annotation() != annotations) fail("check $message (1): ${annotatedType.annotation()} != $annotations")
if (annotatedType.type.toString() != type) fail("check $message (2): ${annotatedType.type} != $type")
}
fun AnnotatedType.annotation() = annotations.joinToString()
@@ -0,0 +1,76 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
// JVM_TARGET: 1.8
// WITH_REFLECT
// FULL_JDK
// FILE: ImplicitReturn.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class ImplicitReturn {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
public @ interface TypeAnn {}
@ImplicitReturn.TypeAnn
public String bar() {
return "OK";
}
}
// FILE: Kotlin.kt
import java.lang.reflect.AnnotatedType
import kotlin.reflect.jvm.javaMethod
import kotlin.reflect.jvm.javaField
import kotlin.test.fail
class Kotlin {
fun foo() = ImplicitReturn().bar()
@JvmField
val field = ImplicitReturn().bar()
}
fun box(): String {
checkTypeAnnotation(
Kotlin::foo.javaMethod!!.annotatedReturnType,
"class java.lang.String",
"@ImplicitReturn\$TypeAnn()",
"foo"
)
checkTypeAnnotation(
Kotlin::field.javaField!!.annotatedType,
"class java.lang.String",
"@ImplicitReturn\$TypeAnn()",
"foo"
)
return Kotlin().foo()
}
fun checkTypeAnnotation(
annotatedType: AnnotatedType,
type: String,
annotations: String,
message: String
) {
if (annotatedType.annotation() != annotations) fail("check $message (1): ${annotatedType.annotation()} != $annotations")
if (annotatedType.type.toString() != type) fail("check $message (2): ${annotatedType.type} != $type")
}
fun AnnotatedType.annotation() = annotations.joinToString()
@@ -0,0 +1,66 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
// JVM_TARGET: 1.8
// WITH_REFLECT
// FULL_JDK
// FILE: A.kt
import java.lang.reflect.AnnotatedType
import kotlin.reflect.jvm.javaMethod
import kotlin.test.fail
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn
fun bar(): @TypeAnn String = "OK"
// FILE: B.kt
import java.lang.reflect.AnnotatedType
import kotlin.reflect.jvm.javaMethod
import kotlin.reflect.jvm.javaField
import kotlin.test.fail
class Kotlin {
fun foo() = bar()
@JvmField
val field = bar()
}
fun box(): String {
checkTypeAnnotation(
Kotlin::foo.javaMethod!!.annotatedReturnType,
"class java.lang.String",
"@TypeAnn()",
"foo"
)
checkTypeAnnotation(
Kotlin::field.javaField!!.annotatedType,
"class java.lang.String",
"@TypeAnn()",
"foo"
)
return Kotlin().foo()
}
fun checkTypeAnnotation(
annotatedType: AnnotatedType,
type: String,
annotations: String,
message: String
) {
if (annotatedType.annotation() != annotations) fail("check $message (1): ${annotatedType.annotation()} != $annotations")
if (annotatedType.type.toString() != type) fail("check $message (2): ${annotatedType.type} != $type")
}
fun AnnotatedType.annotation() = annotations.joinToString()
@@ -0,0 +1,60 @@
// KOTLIN_CONFIGURATION_FLAGS: +JVM.EMIT_JVM_TYPE_ANNOTATIONS
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_REFLECT
// FULL_JDK
// FILE: A.kt
// JVM_TARGET: 1.6
import java.lang.reflect.AnnotatedType
import kotlin.reflect.jvm.javaMethod
import kotlin.test.fail
@Target(AnnotationTarget.TYPE)
annotation class TypeAnn
// FILE: B.kt
// JVM_TARGET: 1.8
import java.lang.reflect.AnnotatedType
import kotlin.reflect.jvm.javaMethod
import kotlin.test.fail
class Kotlin {
fun foo(s: @TypeAnn String) {
}
fun foo2(): @TypeAnn String {
return "OK"
}
}
fun box(): String {
checkTypeAnnotation(
Kotlin::foo.javaMethod!!.annotatedParameterTypes.single(),
"class java.lang.String",
"",
"foo"
)
checkTypeAnnotation(Kotlin::foo2.javaMethod!!.annotatedReturnType, "class java.lang.String", "", "foo2")
return "OK"
}
fun checkTypeAnnotation(
annotatedType: AnnotatedType,
type: String,
annotations: String,
message: String
) {
if (annotatedType.annotation() != annotations) fail("check $message (1): ${annotatedType.annotation()} != $annotations")
if (annotatedType.type.toString() != type) fail("check $message (2): ${annotatedType.type} != $type")
}
fun AnnotatedType.annotation() = annotations.joinToString()
@@ -13,14 +13,17 @@ import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.util.Printer
import org.jetbrains.org.objectweb.asm.util.Textifier
import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor
import java.io.File
private val LINE_SEPARATOR = System.getProperty("line.separator")
abstract class AbstractAsmLikeInstructionListingTest : CodegenTestCase() {
private companion object {
val CURIOUS_ABOUT_DIRECTIVE = "// CURIOUS_ABOUT "
val LOCAL_VARIABLE_TABLE_DIRECTIVE = "// LOCAL_VARIABLE_TABLE"
const val CURIOUS_ABOUT_DIRECTIVE = "// CURIOUS_ABOUT "
const val LOCAL_VARIABLE_TABLE_DIRECTIVE = "// LOCAL_VARIABLE_TABLE"
const val TYPE_ANNOTATIONS_DIRECTIVE = "// TYPE_ANNOTATIONS"
}
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>) {
@@ -40,15 +43,21 @@ abstract class AbstractAsmLikeInstructionListingTest : CodegenTestCase() {
.flatMap { it.split(',').map { it.trim() } }
val showLocalVariables = testFileLines.any { it.trim() == LOCAL_VARIABLE_TABLE_DIRECTIVE }
val showTypeAnnotations = testFileLines.any { it.trim() == TYPE_ANNOTATIONS_DIRECTIVE }
KotlinTestUtils.assertEqualsToFile(txtFile, classes.joinToString(LINE_SEPARATOR.repeat(2)) {
renderClassNode(it, printBytecodeForTheseMethods, showLocalVariables)
renderClassNode(it, printBytecodeForTheseMethods, showLocalVariables, showTypeAnnotations)
})
}
protected open fun getExpectedTextFileName(wholeFile: File): String = wholeFile.nameWithoutExtension + ".txt"
private fun renderClassNode(clazz: ClassNode, showBytecodeForTheseMethods: List<String>, showLocalVariables: Boolean): String {
private fun renderClassNode(
clazz: ClassNode,
showBytecodeForTheseMethods: List<String>,
showLocalVariables: Boolean,
showTypeAnnotations: Boolean
): String {
val fields = (clazz.fields ?: emptyList()).sortedBy { it.name }
val methods = (clazz.methods ?: emptyList()).sortedBy { it.name }
@@ -74,7 +83,7 @@ abstract class AbstractAsmLikeInstructionListingTest : CodegenTestCase() {
methods.joinTo(this, LINE_SEPARATOR.repeat(2)) {
val showBytecode = showBytecodeForTheseMethods.contains(it.name)
renderMethod(it, showBytecode, showLocalVariables).withMargin()
renderMethod(it, showBytecode, showLocalVariables, showTypeAnnotations).withMargin()
}
appendln().append("}")
@@ -88,7 +97,12 @@ abstract class AbstractAsmLikeInstructionListingTest : CodegenTestCase() {
append(field.name)
}
private fun renderMethod(method: MethodNode, showBytecode: Boolean, showLocalVariables: Boolean) = buildString {
private fun renderMethod(
method: MethodNode,
showBytecode: Boolean,
showLocalVariables: Boolean,
showTypeAnnotations: Boolean
) = buildString {
renderVisibilityModifiers(method.access)
renderModalityModifiers(method.access)
val (returnType, parameterTypes) = with(Type.getMethodType(method.desc)) { returnType to argumentTypes }
@@ -100,6 +114,20 @@ abstract class AbstractAsmLikeInstructionListingTest : CodegenTestCase() {
"${type.className} $name"
}.joinTo(this, prefix = "(", postfix = ")")
if (showTypeAnnotations) {
val textifier = Textifier()
val visitor = TraceMethodVisitor(textifier)
method.visibleTypeAnnotations?.forEach {
it.accept(visitor.visitTypeAnnotation(it.typeRef, it.typePath, it.desc, true))
}
method.invisibleTypeAnnotations?.forEach {
it.accept(visitor.visitTypeAnnotation(it.typeRef, it.typePath, it.desc, false))
}
textifier.getText().takeIf { it.isNotEmpty() }?.let {
append("\n${textifier.getText().joinToString("").trimEnd()}")
}
}
val actualShowBytecode = showBytecode && (method.access and ACC_ABSTRACT) == 0
val actualShowLocalVariables = showLocalVariables && method.localVariables?.takeIf { it.isNotEmpty() } != null
@@ -121,6 +149,8 @@ abstract class AbstractAsmLikeInstructionListingTest : CodegenTestCase() {
}
appendln().append("}")
method.visibleTypeAnnotations
}
}
@@ -111,4 +111,82 @@ public class AsmLikeInstructionListingTestGenerated extends AbstractAsmLikeInstr
runTest("compiler/testData/codegen/asmLike/receiverMangling/simple.kt");
}
}
@TestMetadata("compiler/testData/codegen/asmLike/typeAnnotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeAnnotations extends AbstractAsmLikeInstructionListingTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInTypeAnnotations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/asmLike/typeAnnotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("complex.kt")
public void testComplex() throws Exception {
runTest("compiler/testData/codegen/asmLike/typeAnnotations/complex.kt");
}
@TestMetadata("constructor.kt")
public void testConstructor() throws Exception {
runTest("compiler/testData/codegen/asmLike/typeAnnotations/constructor.kt");
}
@TestMetadata("defaultArgs.kt")
public void testDefaultArgs() throws Exception {
runTest("compiler/testData/codegen/asmLike/typeAnnotations/defaultArgs.kt");
}
@TestMetadata("enumClassConstructor.kt")
public void testEnumClassConstructor() throws Exception {
runTest("compiler/testData/codegen/asmLike/typeAnnotations/enumClassConstructor.kt");
}
@TestMetadata("extension.kt")
public void testExtension() throws Exception {
runTest("compiler/testData/codegen/asmLike/typeAnnotations/extension.kt");
}
@TestMetadata("implicit.kt")
public void testImplicit() throws Exception {
runTest("compiler/testData/codegen/asmLike/typeAnnotations/implicit.kt");
}
@TestMetadata("innerClassConstructor.kt")
public void testInnerClassConstructor() throws Exception {
runTest("compiler/testData/codegen/asmLike/typeAnnotations/innerClassConstructor.kt");
}
@TestMetadata("jvmOverload.kt")
public void testJvmOverload() throws Exception {
runTest("compiler/testData/codegen/asmLike/typeAnnotations/jvmOverload.kt");
}
@TestMetadata("jvmStatic.kt")
public void testJvmStatic() throws Exception {
runTest("compiler/testData/codegen/asmLike/typeAnnotations/jvmStatic.kt");
}
@TestMetadata("notYetSupported.kt")
public void testNotYetSupported() throws Exception {
runTest("compiler/testData/codegen/asmLike/typeAnnotations/notYetSupported.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/asmLike/typeAnnotations/simple.kt");
}
@TestMetadata("simple2Params.kt")
public void testSimple2Params() throws Exception {
runTest("compiler/testData/codegen/asmLike/typeAnnotations/simple2Params.kt");
}
@TestMetadata("staticNested.kt")
public void testStaticNested() throws Exception {
runTest("compiler/testData/codegen/asmLike/typeAnnotations/staticNested.kt");
}
}
}
@@ -127,6 +127,24 @@ public class BlackBoxAgainstJavaCodegenTestGenerated extends AbstractBlackBoxAga
runTest("compiler/testData/codegen/boxAgainstJava/annotations/kClassMapping/varargClassParameterOnJavaClass.kt");
}
}
@TestMetadata("compiler/testData/codegen/boxAgainstJava/annotations/typeAnnotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeAnnotations extends AbstractBlackBoxAgainstJavaCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInTypeAnnotations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxAgainstJava/annotations/typeAnnotations"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("implicitReturn.kt")
public void testImplicitReturn() throws Exception {
runTest("compiler/testData/codegen/boxAgainstJava/annotations/typeAnnotations/implicitReturn.kt");
}
}
}
@TestMetadata("compiler/testData/codegen/boxAgainstJava/callableReference")
@@ -248,6 +248,34 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/annotations/annotatedLambda/samLambda.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/annotations/typeAnnotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeAnnotations extends AbstractBlackBoxCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInTypeAnnotations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/typeAnnotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("implicitReturn.kt")
public void testImplicitReturn() throws Exception {
runTest("compiler/testData/codegen/box/annotations/typeAnnotations/implicitReturn.kt");
}
@TestMetadata("methodParameters.kt")
public void testMethodParameters() throws Exception {
runTest("compiler/testData/codegen/box/annotations/typeAnnotations/methodParameters.kt");
}
@TestMetadata("typeUseAnnotation.kt")
public void testTypeUseAnnotation() throws Exception {
runTest("compiler/testData/codegen/box/annotations/typeAnnotations/typeUseAnnotation.kt");
}
}
}
@TestMetadata("compiler/testData/codegen/box/argumentOrder")
@@ -469,4 +469,27 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl
}
}
}
@TestMetadata("compiler/testData/compileKotlinAgainstKotlin/typeAnnotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeAnnotations extends AbstractCompileKotlinAgainstKotlinTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInTypeAnnotations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/compileKotlinAgainstKotlin/typeAnnotations"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("implicitReturn.kt")
public void testImplicitReturn() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/typeAnnotations/implicitReturn.kt");
}
@TestMetadata("typeAnnotationTarget6.kt")
public void testTypeAnnotationTarget6() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/typeAnnotations/typeAnnotationTarget6.kt");
}
}
}
@@ -248,6 +248,34 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/annotations/annotatedLambda/samLambda.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/annotations/typeAnnotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeAnnotations extends AbstractLightAnalysisModeTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInTypeAnnotations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/typeAnnotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("implicitReturn.kt")
public void testImplicitReturn() throws Exception {
runTest("compiler/testData/codegen/box/annotations/typeAnnotations/implicitReturn.kt");
}
@TestMetadata("methodParameters.kt")
public void testMethodParameters() throws Exception {
runTest("compiler/testData/codegen/box/annotations/typeAnnotations/methodParameters.kt");
}
@TestMetadata("typeUseAnnotation.kt")
public void testTypeUseAnnotation() throws Exception {
runTest("compiler/testData/codegen/box/annotations/typeAnnotations/typeUseAnnotation.kt");
}
}
}
@TestMetadata("compiler/testData/codegen/box/argumentOrder")
@@ -248,6 +248,34 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/annotations/annotatedLambda/samLambda.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/annotations/typeAnnotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeAnnotations extends AbstractFirBlackBoxCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTestWithCustomIgnoreDirective(this::doTest, TargetBackend.JVM_IR, testDataFilePath, "// IGNORE_BACKEND_FIR: ");
}
public void testAllFilesPresentInTypeAnnotations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/typeAnnotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("implicitReturn.kt")
public void testImplicitReturn() throws Exception {
runTest("compiler/testData/codegen/box/annotations/typeAnnotations/implicitReturn.kt");
}
@TestMetadata("methodParameters.kt")
public void testMethodParameters() throws Exception {
runTest("compiler/testData/codegen/box/annotations/typeAnnotations/methodParameters.kt");
}
@TestMetadata("typeUseAnnotation.kt")
public void testTypeUseAnnotation() throws Exception {
runTest("compiler/testData/codegen/box/annotations/typeAnnotations/typeUseAnnotation.kt");
}
}
}
@TestMetadata("compiler/testData/codegen/box/argumentOrder")
@@ -128,6 +128,24 @@ public class IrBlackBoxAgainstJavaCodegenTestGenerated extends AbstractIrBlackBo
runTest("compiler/testData/codegen/boxAgainstJava/annotations/kClassMapping/varargClassParameterOnJavaClass.kt");
}
}
@TestMetadata("compiler/testData/codegen/boxAgainstJava/annotations/typeAnnotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeAnnotations extends AbstractIrBlackBoxAgainstJavaCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
}
public void testAllFilesPresentInTypeAnnotations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/boxAgainstJava/annotations/typeAnnotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("implicitReturn.kt")
public void testImplicitReturn() throws Exception {
runTest("compiler/testData/codegen/boxAgainstJava/annotations/typeAnnotations/implicitReturn.kt");
}
}
}
@TestMetadata("compiler/testData/codegen/boxAgainstJava/callableReference")
@@ -248,6 +248,34 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/annotations/annotatedLambda/samLambda.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/annotations/typeAnnotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeAnnotations extends AbstractIrBlackBoxCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
}
public void testAllFilesPresentInTypeAnnotations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/typeAnnotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("implicitReturn.kt")
public void testImplicitReturn() throws Exception {
runTest("compiler/testData/codegen/box/annotations/typeAnnotations/implicitReturn.kt");
}
@TestMetadata("methodParameters.kt")
public void testMethodParameters() throws Exception {
runTest("compiler/testData/codegen/box/annotations/typeAnnotations/methodParameters.kt");
}
@TestMetadata("typeUseAnnotation.kt")
public void testTypeUseAnnotation() throws Exception {
runTest("compiler/testData/codegen/box/annotations/typeAnnotations/typeUseAnnotation.kt");
}
}
}
@TestMetadata("compiler/testData/codegen/box/argumentOrder")
@@ -464,4 +464,27 @@ public class IrCompileKotlinAgainstKotlinTestGenerated extends AbstractIrCompile
}
}
}
@TestMetadata("compiler/testData/compileKotlinAgainstKotlin/typeAnnotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeAnnotations extends AbstractIrCompileKotlinAgainstKotlinTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
}
public void testAllFilesPresentInTypeAnnotations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/compileKotlinAgainstKotlin/typeAnnotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("implicitReturn.kt")
public void testImplicitReturn() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/typeAnnotations/implicitReturn.kt");
}
@TestMetadata("typeAnnotationTarget6.kt")
public void testTypeAnnotationTarget6() throws Exception {
runTest("compiler/testData/compileKotlinAgainstKotlin/typeAnnotations/typeAnnotationTarget6.kt");
}
}
}
@@ -78,6 +78,19 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/annotatedLambda"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
}
@TestMetadata("compiler/testData/codegen/box/annotations/typeAnnotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeAnnotations extends AbstractIrJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public void testAllFilesPresentInTypeAnnotations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/typeAnnotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
}
}
@TestMetadata("compiler/testData/codegen/box/argumentOrder")
@@ -78,6 +78,19 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/annotatedLambda"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
}
@TestMetadata("compiler/testData/codegen/box/annotations/typeAnnotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TypeAnnotations extends AbstractJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public void testAllFilesPresentInTypeAnnotations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/annotations/typeAnnotations"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
}
}
@TestMetadata("compiler/testData/codegen/box/argumentOrder")