JVM_IR. Support type annotations
This commit is contained in:
+64
-9
@@ -23,6 +23,10 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.TypeAnnotationCollector
|
||||
import org.jetbrains.kotlin.codegen.TypePathInfo
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.JvmTarget.JVM_1_6
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
@@ -33,18 +37,21 @@ import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.isMarkedNullable
|
||||
import org.jetbrains.kotlin.ir.types.isNullable
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.synthetic.isVisibleOutside
|
||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import java.lang.annotation.RetentionPolicy
|
||||
|
||||
class AnnotationCodegen(
|
||||
abstract class AnnotationCodegen(
|
||||
private val innerClassConsumer: InnerClassConsumer,
|
||||
context: JvmBackendContext,
|
||||
private val visitAnnotation: (descriptor: String, visible: Boolean) -> AnnotationVisitor
|
||||
private val context: JvmBackendContext
|
||||
) {
|
||||
private val typeMapper = context.typeMapper
|
||||
private val methodSignatureMapper = context.methodSignatureMapper
|
||||
@@ -52,7 +59,7 @@ class AnnotationCodegen(
|
||||
/**
|
||||
* @param returnType can be null if not applicable (e.g. [annotated] is a class)
|
||||
*/
|
||||
fun genAnnotations(annotated: IrAnnotationContainer?, returnType: Type?) {
|
||||
fun genAnnotations(annotated: IrAnnotationContainer?, returnType: Type?, typeForTypeAnnotations: IrType?) {
|
||||
if (annotated == null) return
|
||||
|
||||
val annotationDescriptorsAlreadyPresent = mutableSetOf<String>()
|
||||
@@ -84,14 +91,26 @@ class AnnotationCodegen(
|
||||
}
|
||||
}
|
||||
|
||||
genAnnotation(annotation)?.let { descriptor ->
|
||||
genAnnotation(annotation, null, false)?.let { descriptor ->
|
||||
annotationDescriptorsAlreadyPresent.add(descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
generateAdditionalAnnotations(annotated, returnType, annotationDescriptorsAlreadyPresent)
|
||||
generateTypeAnnotations(annotated, typeForTypeAnnotations)
|
||||
}
|
||||
|
||||
abstract fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor
|
||||
|
||||
open fun visitTypeAnnotation(
|
||||
descr: String?,
|
||||
path: TypePath?,
|
||||
visible: Boolean,
|
||||
): AnnotationVisitor {
|
||||
throw RuntimeException("Not implemented")
|
||||
}
|
||||
|
||||
|
||||
private fun generateAdditionalAnnotations(
|
||||
annotated: IrAnnotationContainer,
|
||||
returnType: Type?,
|
||||
@@ -152,7 +171,7 @@ class AnnotationCodegen(
|
||||
visitor.visitEnd()
|
||||
}
|
||||
|
||||
private fun genAnnotation(annotation: IrConstructorCall): String? {
|
||||
private fun genAnnotation(annotation: IrConstructorCall, path: TypePath?, isTypeAnnotation: Boolean): String? {
|
||||
val annotationClass = annotation.annotationClass
|
||||
val retentionPolicy = getRetentionPolicy(annotationClass)
|
||||
if (retentionPolicy == RetentionPolicy.SOURCE) return null
|
||||
@@ -167,7 +186,9 @@ class AnnotationCodegen(
|
||||
innerClassConsumer.addInnerClassInfoFromAnnotation(annotationClass)
|
||||
|
||||
val asmTypeDescriptor = typeMapper.mapType(annotation.type).descriptor
|
||||
val annotationVisitor = visitAnnotation(asmTypeDescriptor, retentionPolicy == RetentionPolicy.RUNTIME)
|
||||
val annotationVisitor =
|
||||
if (!isTypeAnnotation) visitAnnotation(asmTypeDescriptor, retentionPolicy == RetentionPolicy.RUNTIME) else
|
||||
visitTypeAnnotation(asmTypeDescriptor, path, retentionPolicy == RetentionPolicy.RUNTIME)
|
||||
|
||||
genAnnotationArguments(annotation, annotationVisitor)
|
||||
annotationVisitor.visitEnd()
|
||||
@@ -281,6 +302,40 @@ class AnnotationCodegen(
|
||||
|
||||
val IrConstructorCall.annotationClass get() = symbol.owner.parentAsClass
|
||||
}
|
||||
|
||||
private fun generateTypeAnnotations(
|
||||
annotated: IrAnnotationContainer,
|
||||
type: IrType?
|
||||
) {
|
||||
if ((annotated as? IrDeclaration)?.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR ||
|
||||
type == null || context.state.target === JVM_1_6 ||
|
||||
!context.state.configuration.getBoolean(JVMConfigurationKeys.EMIT_JVM_TYPE_ANNOTATIONS)
|
||||
) {
|
||||
return
|
||||
}
|
||||
val infos: Iterable<TypePathInfo<IrConstructorCall>> =
|
||||
IrTypeAnnotationCollector(context.typeMapper.typeSystem).collectTypeAnnotations(type)
|
||||
for (info in infos) {
|
||||
for (annotation in info.annotations) {
|
||||
genAnnotation(annotation, info.path, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class IrTypeAnnotationCollector(context: TypeSystemCommonBackendContext) : TypeAnnotationCollector<IrConstructorCall>(context) {
|
||||
|
||||
override fun KotlinTypeMarker.extractAnnotations(): List<IrConstructorCall> {
|
||||
require(this is IrType)
|
||||
return 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.origin != IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB &&
|
||||
it.annotationClass.origin != IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB) ||
|
||||
isCompiledToJvm8OrHigher(it.annotationClass.descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface InnerClassConsumer {
|
||||
|
||||
+19
-4
@@ -45,8 +45,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import java.io.File
|
||||
|
||||
open class ClassCodegen protected constructor(
|
||||
@@ -125,7 +124,15 @@ open class ClassCodegen protected constructor(
|
||||
signature.superclassName,
|
||||
signature.interfaces.toTypedArray()
|
||||
)
|
||||
AnnotationCodegen(this, context, visitor.visitor::visitAnnotation).genAnnotations(irClass, null)
|
||||
object : AnnotationCodegen(this@ClassCodegen, context) {
|
||||
override fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor {
|
||||
return visitor.visitor.visitAnnotation(descr, visible)
|
||||
}
|
||||
}.genAnnotations(
|
||||
irClass,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
val nestedClasses = irClass.declarations.mapNotNull { declaration ->
|
||||
if (declaration is IrClass) {
|
||||
@@ -328,7 +335,15 @@ open class ClassCodegen protected constructor(
|
||||
fieldSignature, (field.initializer?.expression as? IrConst<*>)?.value
|
||||
)
|
||||
|
||||
AnnotationCodegen(this, context, fv::visitAnnotation).genAnnotations(field, fieldType)
|
||||
object : AnnotationCodegen(this@ClassCodegen, context) {
|
||||
override fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor {
|
||||
return fv.visitAnnotation(descr, visible)
|
||||
}
|
||||
|
||||
override fun visitTypeAnnotation(descr: String?, path: TypePath?, visible: Boolean): AnnotationVisitor {
|
||||
return fv.visitTypeAnnotation(TypeReference.newTypeReference(TypeReference.FIELD).value,path, descr, visible)
|
||||
}
|
||||
}.genAnnotations(field, fieldType, field.type)
|
||||
|
||||
val descriptor = field.metadata?.descriptor
|
||||
if (descriptor != null) {
|
||||
|
||||
+39
-13
@@ -34,14 +34,13 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
open class FunctionCodegen(
|
||||
private val irFunction: IrFunction,
|
||||
private val classCodegen: ClassCodegen,
|
||||
private val inlinedInto: ExpressionCodegen? = null
|
||||
private val inlinedInto: ExpressionCodegen? = null,
|
||||
) {
|
||||
val context = classCodegen.context
|
||||
val state = classCodegen.state
|
||||
@@ -65,9 +64,20 @@ open class FunctionCodegen(
|
||||
}
|
||||
|
||||
if (irFunction.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) {
|
||||
AnnotationCodegen(classCodegen, context, methodVisitor::visitAnnotation).genAnnotations(
|
||||
object : AnnotationCodegen(classCodegen, context) {
|
||||
override fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor {
|
||||
return methodVisitor.visitAnnotation(descr, visible)
|
||||
}
|
||||
|
||||
override fun visitTypeAnnotation(descr: String?, path: TypePath?, visible: Boolean): AnnotationVisitor {
|
||||
return methodVisitor.visitTypeAnnotation(
|
||||
TypeReference.newTypeReference(TypeReference.METHOD_RETURN).value, path, descr, visible
|
||||
)
|
||||
}
|
||||
}.genAnnotations(
|
||||
functionView,
|
||||
signature.asmMethod.returnType
|
||||
signature.asmMethod.returnType,
|
||||
irFunction.returnType
|
||||
)
|
||||
// Not generating parameter annotations for default stubs fixes KT-7892, though
|
||||
// this certainly looks like a workaround for a javac bug.
|
||||
@@ -216,7 +226,14 @@ open class FunctionCodegen(
|
||||
|
||||
private fun generateAnnotationDefaultValueIfNeeded(methodVisitor: MethodVisitor) {
|
||||
getAnnotationDefaultValueExpression()?.let { defaultValueExpression ->
|
||||
val annotationCodegen = AnnotationCodegen(classCodegen, context) { _, _ -> methodVisitor.visitAnnotationDefault() }
|
||||
val annotationCodegen = object: AnnotationCodegen(
|
||||
classCodegen,
|
||||
context
|
||||
) {
|
||||
override fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor {
|
||||
return methodVisitor.visitAnnotationDefault()
|
||||
}
|
||||
}
|
||||
annotationCodegen.generateAnnotationDefaultValue(defaultValueExpression)
|
||||
}
|
||||
}
|
||||
@@ -282,13 +299,22 @@ private fun generateParameterAnnotations(
|
||||
}
|
||||
|
||||
if (!kind.isSkippedInGenericSignature) {
|
||||
AnnotationCodegen(innerClassConsumer, context) { descriptor, visible ->
|
||||
mv.visitParameterAnnotation(
|
||||
i - syntheticParameterCount,
|
||||
descriptor,
|
||||
visible
|
||||
)
|
||||
}.genAnnotations(annotated, parameterSignature.asmType)
|
||||
object : AnnotationCodegen(innerClassConsumer, context) {
|
||||
override fun visitAnnotation(descr: String?, visible: Boolean): AnnotationVisitor {
|
||||
return mv.visitParameterAnnotation(
|
||||
i - syntheticParameterCount,
|
||||
descr,
|
||||
visible
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitTypeAnnotation(descr: String?, path: TypePath?, visible: Boolean): AnnotationVisitor {
|
||||
return mv.visitTypeAnnotation(
|
||||
TypeReference.newFormalParameterReference(i - syntheticParameterCount).value,
|
||||
path, descr, visible
|
||||
)
|
||||
}
|
||||
}.genAnnotations(annotated, parameterSignature.asmType, annotated?.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,6 +310,9 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon
|
||||
override fun TypeConstructorMarker.isInlineClass(): Boolean =
|
||||
(this as? IrClassSymbol)?.owner?.isInline == true
|
||||
|
||||
override fun TypeConstructorMarker.isInnerClass(): Boolean =
|
||||
(this as? IrClassSymbol)?.owner?.isInner == true
|
||||
|
||||
override fun TypeParameterMarker.getRepresentativeUpperBound(): KotlinTypeMarker =
|
||||
(this as IrTypeParameterSymbol).owner.superTypes.firstOrNull {
|
||||
val irClass = it.classOrNull?.owner ?: return@firstOrNull false
|
||||
|
||||
Reference in New Issue
Block a user