Load default values for annotation members from classfiles
so that defaults are available to synthetic implementations. #KT-48181 Fixed Implementation is for JVM IR; other backends & FIR need to be supported separately.
This commit is contained in:
+6
@@ -467,6 +467,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/annotations/instances/multifileEqHc.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multimoduleCreation.kt")
|
||||
public void testMultimoduleCreation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/annotations/instances/multimoduleCreation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multimoduleInlining.kt")
|
||||
public void testMultimoduleInlining() throws Exception {
|
||||
|
||||
+8
-4
@@ -80,17 +80,20 @@ internal class AnnotationsLoader(private val session: FirSession, private val ko
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitClassLiteral(name: Name, value: ClassLiteralValue) {
|
||||
override fun visitClassLiteral(name: Name?, value: ClassLiteralValue) {
|
||||
if (name == null) return
|
||||
argumentMap[name] = buildGetClassCall {
|
||||
argumentList = buildUnaryArgumentList(value.toFirClassReferenceExpression())
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitEnum(name: Name, enumClassId: ClassId, enumEntryName: Name) {
|
||||
override fun visitEnum(name: Name?, enumClassId: ClassId, enumEntryName: Name) {
|
||||
if (name == null) return
|
||||
argumentMap[name] = enumClassId.toEnumEntryReferenceExpression(enumEntryName)
|
||||
}
|
||||
|
||||
override fun visitArray(name: Name): KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor {
|
||||
override fun visitArray(name: Name?): KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor? {
|
||||
if (name == null) return null
|
||||
return object : KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor {
|
||||
private val elements = mutableListOf<FirExpression>()
|
||||
|
||||
@@ -131,7 +134,8 @@ internal class AnnotationsLoader(private val session: FirSession, private val ko
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitAnnotation(name: Name, classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor {
|
||||
override fun visitAnnotation(name: Name?, classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
|
||||
if (name == null) return null
|
||||
val list = mutableListOf<FirAnnotation>()
|
||||
val visitor = loadAnnotation(classId, list)
|
||||
return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor by visitor {
|
||||
|
||||
+5
@@ -322,6 +322,11 @@ private fun FirSession.loadMemberAnnotations(
|
||||
}
|
||||
return annotationsLoader.loadAnnotationIfNotSpecial(classId, result)
|
||||
}
|
||||
|
||||
override fun visitAnnotationMemberDefaultValue(): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
|
||||
// TODO: load annotation default values to properly support annotation instantiation feature
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
open inner class MemberAnnotationVisitor(protected val signature: MemberSignature) : KotlinJvmBinaryClass.AnnotationVisitor {
|
||||
|
||||
+13
-5
@@ -173,17 +173,18 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
|
||||
return new org.jetbrains.org.objectweb.asm.AnnotationVisitor(API_VERSION) {
|
||||
@Override
|
||||
public void visit(String name, @NotNull Object value) {
|
||||
Name identifier = name == null ? null : Name.identifier(name);
|
||||
if (value instanceof Type) {
|
||||
v.visitClassLiteral(Name.identifier(name), resolveKotlinNameByType((Type) value, innerClasses));
|
||||
v.visitClassLiteral(identifier, resolveKotlinNameByType((Type) value, innerClasses));
|
||||
}
|
||||
else {
|
||||
v.visit(name == null ? null : Name.identifier(name), value);
|
||||
v.visit(identifier, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.jetbrains.org.objectweb.asm.AnnotationVisitor visitArray(String name) {
|
||||
AnnotationArrayArgumentVisitor arv = v.visitArray(Name.identifier(name));
|
||||
AnnotationArrayArgumentVisitor arv = v.visitArray(name == null ? null : Name.identifier(name));
|
||||
return arv == null ? null : new org.jetbrains.org.objectweb.asm.AnnotationVisitor(API_VERSION) {
|
||||
@Override
|
||||
public void visit(String name, @NotNull Object value) {
|
||||
@@ -215,13 +216,14 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
|
||||
|
||||
@Override
|
||||
public org.jetbrains.org.objectweb.asm.AnnotationVisitor visitAnnotation(String name, @NotNull String desc) {
|
||||
AnnotationArgumentVisitor arv = v.visitAnnotation(Name.identifier(name), resolveNameByDesc(desc, innerClasses));
|
||||
AnnotationArgumentVisitor arv =
|
||||
v.visitAnnotation(name == null ? null : Name.identifier(name), resolveNameByDesc(desc, innerClasses));
|
||||
return arv == null ? null : convertAnnotationVisitor(arv, innerClasses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(String name, @NotNull String desc, @NotNull String value) {
|
||||
v.visitEnum(Name.identifier(name), resolveNameByDesc(desc, innerClasses), Name.identifier(value));
|
||||
v.visitEnum(name == null ? null : Name.identifier(name), resolveNameByDesc(desc, innerClasses), Name.identifier(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -269,6 +271,12 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
|
||||
return convertAnnotationVisitor(v, desc, innerClasses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.jetbrains.org.objectweb.asm.AnnotationVisitor visitAnnotationDefault() {
|
||||
AnnotationArgumentVisitor av = v.visitAnnotationMemberDefaultValue();
|
||||
return av == null ? null : convertAnnotationVisitor(av, innerClasses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.jetbrains.org.objectweb.asm.AnnotationVisitor visitParameterAnnotation(int parameter, @NotNull String desc, boolean visible) {
|
||||
int parameterIndex = parameter + methodParamCount - (visible ? visibleAnnotableParameterCount : invisibleAnnotableParameterCount);
|
||||
|
||||
+11
-6
@@ -15,12 +15,12 @@ import org.jetbrains.kotlin.backend.jvm.ir.isInPublicInlineScope
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.javaClassReference
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
@@ -136,11 +136,16 @@ class JvmAnnotationImplementationTransformer(val jvmContext: JvmBackendContext,
|
||||
}.also { it.parent = implClass }
|
||||
|
||||
val parameter = generatedConstructor.addValueParameter(propName.asString(), propType)
|
||||
// VALUE_FROM_PARAMETER
|
||||
val originalParameter = ((property.backingField?.initializer?.expression as? IrGetValue)?.symbol?.owner as? IrValueParameter)
|
||||
if (originalParameter?.defaultValue != null) {
|
||||
parameter.defaultValue = originalParameter.defaultValue!!.deepCopyWithVariables().also { it.transformChildrenVoid() }
|
||||
}
|
||||
|
||||
val defaultExpression = property.backingField?.initializer?.expression
|
||||
val newDefaultValue: IrExpressionBody? =
|
||||
if (defaultExpression is IrGetValue && defaultExpression.symbol.owner is IrValueParameter) {
|
||||
// INITIALIZE_PROPERTY_FROM_PARAMETER
|
||||
(defaultExpression.symbol.owner as IrValueParameter).defaultValue
|
||||
} else if (defaultExpression != null) {
|
||||
property.backingField!!.initializer
|
||||
} else null
|
||||
parameter.defaultValue = newDefaultValue?.deepCopyWithVariables()?.also { it.transformChildrenVoid() }
|
||||
|
||||
ctorBody.statements += IrSetFieldImpl(
|
||||
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, field.symbol,
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// TARGET_BACKEND: JVM_IR
|
||||
// IGNORE_DEXING
|
||||
// WITH_RUNTIME
|
||||
// !LANGUAGE: +InstantiationOfAnnotationClasses
|
||||
|
||||
// MODULE: lib
|
||||
// FILE: lib.kt
|
||||
|
||||
package a
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
annotation class A(val kClass: KClass<*> = Int::class)
|
||||
|
||||
annotation class OtherArrays(
|
||||
val doublesArray: DoubleArray = [],
|
||||
val enumArray: Array<kotlin.text.RegexOption> = [],
|
||||
val annotationsArray: Array<JvmStatic> = [],
|
||||
val namesArray: Array<JvmName> = [JvmName("foo")]
|
||||
)
|
||||
|
||||
// Uncomment when KT-49998 is resolved
|
||||
//annotation class UnsignedValue(
|
||||
// val uint: UInt = 2147483657U // Int.MAX_VALUE + 10
|
||||
//)
|
||||
|
||||
// MODULE: app(lib)
|
||||
// FILE: app.kt
|
||||
|
||||
// kotlin.Metadata: IntArray, Array<String>
|
||||
// kotlin.Deprecated: Nested annotation, enum instance
|
||||
// a.A: KClass
|
||||
// a.OtherArrays: Arrays of enums and other annotations
|
||||
|
||||
package test
|
||||
|
||||
import a.*
|
||||
import kotlin.test.*
|
||||
|
||||
class C {
|
||||
fun one(): A = A()
|
||||
fun two(): Metadata = Metadata()
|
||||
fun three(): Deprecated = Deprecated("foo")
|
||||
fun four(): OtherArrays = OtherArrays()
|
||||
// fun five(): UnsignedValue = UnsignedValue()
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val a = C().one()
|
||||
assertEquals(Int::class, a.kClass)
|
||||
assertEquals(
|
||||
"""@kotlin.Metadata(bytecodeVersion=[1, 0, 3], data1=[], data2=[], extraInt=0, extraString=, kind=1, metadataVersion=[], packageName=)""",
|
||||
C().two().toString()
|
||||
)
|
||||
assertEquals(
|
||||
"""@kotlin.Deprecated(level=WARNING, message=foo, replaceWith=@kotlin.ReplaceWith(expression=, imports=[]))""",
|
||||
C().three().toString()
|
||||
)
|
||||
assertEquals(
|
||||
"""@a.OtherArrays(annotationsArray=[], doublesArray=[], enumArray=[], namesArray=[@kotlin.jvm.JvmName(name=foo)])""",
|
||||
C().four().toString()
|
||||
)
|
||||
// assertEquals(Int.MAX_VALUE.toUInt() + 10.toUInt(), C().five().uint)
|
||||
return "OK"
|
||||
}
|
||||
+2
@@ -1,4 +1,6 @@
|
||||
// ALLOW_AST_ACCESS
|
||||
// NO_CHECK_SOURCE_VS_BINARY
|
||||
//^ While compiling source, we do not store annotation default values, but we load them when reading compiled files
|
||||
package test
|
||||
|
||||
annotation class Anno(val value: String = "0", val x: Int = 0)
|
||||
|
||||
+2
-2
@@ -2,9 +2,9 @@ package test
|
||||
|
||||
public final annotation class Anno : kotlin.Annotation {
|
||||
/*primary*/ public constructor Anno(/*0*/ value: kotlin.String = ..., /*1*/ x: kotlin.Int = ...)
|
||||
public final val value: kotlin.String
|
||||
public final val value: kotlin.String = "0"
|
||||
public final fun <get-value>(): kotlin.String
|
||||
public final val x: kotlin.Int
|
||||
public final val x: kotlin.Int = 0
|
||||
public final fun <get-x>(): kotlin.Int
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
//ALLOW_AST_ACCESS
|
||||
// NO_CHECK_SOURCE_VS_BINARY
|
||||
//^ While compiling source, we do not store annotation default values, but we load them when reading compiled files
|
||||
package test
|
||||
|
||||
@Target(AnnotationTarget.TYPEALIAS)
|
||||
|
||||
@@ -2,7 +2,7 @@ package test
|
||||
|
||||
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.TYPEALIAS}) public final annotation class Ann : kotlin.Annotation {
|
||||
/*primary*/ public constructor Ann(/*0*/ value: kotlin.String = ...)
|
||||
public final val value: kotlin.String
|
||||
public final val value: kotlin.String = ""
|
||||
public final fun <get-value>(): kotlin.String
|
||||
}
|
||||
@test.Ann public typealias A1 = kotlin.String
|
||||
|
||||
+6
@@ -467,6 +467,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/annotations/instances/multifileEqHc.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multimoduleCreation.kt")
|
||||
public void testMultimoduleCreation() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/annotations/instances/multimoduleCreation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("multimoduleInlining.kt")
|
||||
public void testMultimoduleInlining() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user