From aeba124bdb6dfe4377b3912773312e5428926aac Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 14 Sep 2016 19:52:57 +0300 Subject: [PATCH] Support Kotlin annotation constructors in reflection #KT-13106 In Progress --- .../constructors/annotationClass.kt | 21 ++++ .../classesWithoutConstructors.kt | 3 - .../createAnnotation/arrayOfKClasses.kt | 12 +++ .../createAnnotation/callByKotlin.kt | 50 ++++++++++ .../reflection/createAnnotation/callKotlin.kt | 35 +++++++ .../types/annotationConstructorParameters.kt | 48 ++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 39 ++++++++ .../internal/AnnotationConstructorCaller.kt | 95 +++++++++++++++++++ .../reflect/jvm/internal/FunctionCaller.kt | 4 +- .../reflect/jvm/internal/KCallableImpl.kt | 29 +++++- .../kotlin/reflect/jvm/internal/KClassImpl.kt | 6 +- .../reflect/jvm/internal/KFunctionImpl.kt | 16 +++- 12 files changed, 344 insertions(+), 14 deletions(-) create mode 100644 compiler/testData/codegen/box/reflection/constructors/annotationClass.kt create mode 100644 compiler/testData/codegen/box/reflection/createAnnotation/arrayOfKClasses.kt create mode 100644 compiler/testData/codegen/box/reflection/createAnnotation/callByKotlin.kt create mode 100644 compiler/testData/codegen/box/reflection/createAnnotation/callKotlin.kt create mode 100644 compiler/testData/codegen/box/reflection/mapping/types/annotationConstructorParameters.kt create mode 100644 core/reflection.jvm/src/kotlin/reflect/jvm/internal/AnnotationConstructorCaller.kt diff --git a/compiler/testData/codegen/box/reflection/constructors/annotationClass.kt b/compiler/testData/codegen/box/reflection/constructors/annotationClass.kt new file mode 100644 index 00000000000..03d29798d37 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/constructors/annotationClass.kt @@ -0,0 +1,21 @@ +// WITH_REFLECT + +import kotlin.reflect.* +import kotlin.test.assertEquals + +annotation class A1 + +annotation class A2(val k: KClass<*>, val s: A1) + +fun box(): String { + assertEquals(1, A1::class.constructors.size) + assertEquals(A1::class.primaryConstructor, A1::class.constructors.single()) + + val cs = A2::class.constructors + assertEquals(1, cs.size) + assertEquals(A2::class.primaryConstructor, cs.single()) + val params = cs.single().parameters + assertEquals(listOf("k", "s"), params.map { it.name }) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/constructors/classesWithoutConstructors.kt b/compiler/testData/codegen/box/reflection/constructors/classesWithoutConstructors.kt index 67a43153b3b..c2ce375b0ec 100644 --- a/compiler/testData/codegen/box/reflection/constructors/classesWithoutConstructors.kt +++ b/compiler/testData/codegen/box/reflection/constructors/classesWithoutConstructors.kt @@ -1,10 +1,8 @@ // WITH_REFLECT -import kotlin.reflect.* import kotlin.test.assertTrue interface Interface -annotation class Anno(val x: Int) object Obj class C { @@ -13,7 +11,6 @@ class C { fun box(): String { assertTrue(Interface::class.constructors.isEmpty()) - assertTrue(Anno::class.constructors.isEmpty()) assertTrue(Obj::class.constructors.isEmpty()) assertTrue(C.Companion::class.constructors.isEmpty()) diff --git a/compiler/testData/codegen/box/reflection/createAnnotation/arrayOfKClasses.kt b/compiler/testData/codegen/box/reflection/createAnnotation/arrayOfKClasses.kt new file mode 100644 index 00000000000..69fca655d33 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/createAnnotation/arrayOfKClasses.kt @@ -0,0 +1,12 @@ +// WITH_REFLECT + +import kotlin.reflect.KClass +import kotlin.test.assertEquals + +annotation class Anno(val klasses: Array> = arrayOf(String::class, Int::class)) + +fun box(): String { + val anno = Anno::class.constructors.single().callBy(emptyMap()) + assertEquals(listOf(String::class, Int::class), (anno.klasses as Array>).toList() /* TODO: KT-9453 */) + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/createAnnotation/callByKotlin.kt b/compiler/testData/codegen/box/reflection/createAnnotation/callByKotlin.kt new file mode 100644 index 00000000000..ea750461c3d --- /dev/null +++ b/compiler/testData/codegen/box/reflection/createAnnotation/callByKotlin.kt @@ -0,0 +1,50 @@ +// WITH_REFLECT + +import kotlin.reflect.KClass +import kotlin.reflect.primaryConstructor +import kotlin.test.assertEquals +import kotlin.test.assertFails + +annotation class NoParams +annotation class OneDefault(val s: String = "OK") +annotation class OneNonDefault(val s: String) +annotation class TwoParamsOneDefault(val s: String, val x: Int = 42) +annotation class TwoParamsOneDefaultKClass(val string: String, val klass: KClass<*> = Number::class) +annotation class TwoNonDefaults(val string: String, val klass: KClass<*>) + + +inline fun create(args: Map): T { + val ctor = T::class.constructors.single() + return ctor.callBy(args.mapKeys { entry -> ctor.parameters.single { it.name == entry.key } }) +} + +inline fun create(): T = create(emptyMap()) + +fun box(): String { + create() + + val t1 = create() + assertEquals("OK", t1.s) + assertFails { create(mapOf("s" to 42)) } + + val t2 = create(mapOf("s" to "OK")) + assertEquals("OK", t2.s) + assertFails { create() } + + val t3 = create(mapOf("s" to "OK")) + assertEquals("OK", t3.s) + assertEquals(42, t3.x) + val t4 = create(mapOf("s" to "OK", "x" to 239)) + assertEquals(239, t4.x) + assertFails { create(mapOf("s" to "Fail", "x" to "Fail")) } + + val t5 = create(mapOf("string" to "OK")) + assertEquals(Number::class, t5.klass as KClass<*> /* TODO: KT-9453 */) + + assertFails("KClass (not Class) instances should be passed as arguments") { + create(mapOf("klass" to String::class.java, "string" to "Fail")) + } + + val t6 = create(mapOf("klass" to String::class, "string" to "OK")) + return t6.string +} diff --git a/compiler/testData/codegen/box/reflection/createAnnotation/callKotlin.kt b/compiler/testData/codegen/box/reflection/createAnnotation/callKotlin.kt new file mode 100644 index 00000000000..094e82572fe --- /dev/null +++ b/compiler/testData/codegen/box/reflection/createAnnotation/callKotlin.kt @@ -0,0 +1,35 @@ +// WITH_REFLECT + +import kotlin.reflect.KClass +import kotlin.reflect.primaryConstructor +import kotlin.test.assertEquals +import kotlin.test.assertFails + +annotation class NoParams +annotation class OneDefault(val s: String = "Fail") +annotation class TwoNonDefaults(val string: String, val klass: KClass<*>) + +inline fun create(vararg args: Any?): T = + T::class.constructors.single().call(*args) + +fun box(): String { + create() + assertFails { create("Fail") } + + assertFails { create() } + assertFails { create(42) } + val o = create("OK") + assertEquals("OK", o.s) + + assertFails("call() should fail because arguments were passed in an incorrect order") { + create(Any::class, "Fail") + } + assertFails("call() should fail because KClass (not Class) instances should be passed as arguments") { + create("Fail", Any::class.java) + } + + val k = create("OK", Int::class) + assertEquals(Int::class, k.klass as KClass<*> /* TODO: KT-9453 */) + + return k.string +} diff --git a/compiler/testData/codegen/box/reflection/mapping/types/annotationConstructorParameters.kt b/compiler/testData/codegen/box/reflection/mapping/types/annotationConstructorParameters.kt new file mode 100644 index 00000000000..87b7f1ea0f7 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/mapping/types/annotationConstructorParameters.kt @@ -0,0 +1,48 @@ +// WITH_REFLECT +// FULL_JDK + +import java.lang.reflect.GenericArrayType +import java.lang.reflect.ParameterizedType +import kotlin.reflect.KClass +import kotlin.reflect.jvm.javaType +import kotlin.test.assertEquals +import kotlin.test.assertTrue + +annotation class Z +enum class E + +annotation class Anno( + val b: Byte, + val s: String, + val ss: Array, + val z: Z, + val zs: Array, + val e: E, + val es: Array, + val k: KClass<*>, + val ka: Array> +) + +fun tmp(): Array> = null!! + +fun box(): String { + val t = Anno::class.constructors.single().parameters.map { it.type.javaType } + + assertEquals(Byte::class.java, t[0]) + assertEquals(String::class.java, t[1]) + assertEquals(Array::class.java, t[2]) + assertEquals(Z::class.java, t[3]) + assertEquals(Array::class.java, t[4]) + assertEquals(E::class.java, t[5]) + assertEquals(Array::class.java, t[6]) + + assertTrue(t[7] is ParameterizedType) + assertEquals(Class::class.java, (t[7] as ParameterizedType).rawType) + + assertTrue(t[8] is GenericArrayType) + val e = (t[8] as GenericArrayType).genericComponentType + assertTrue(e is ParameterizedType) + assertEquals(Class::class.java, (e as ParameterizedType).rawType) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 5d54ea75f7d..fda259d825a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -12111,6 +12111,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/constructors"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("annotationClass.kt") + public void testAnnotationClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/constructors/annotationClass.kt"); + doTest(fileName); + } + @TestMetadata("classesWithoutConstructors.kt") public void testClassesWithoutConstructors() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/constructors/classesWithoutConstructors.kt"); @@ -12136,6 +12142,33 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } + @TestMetadata("compiler/testData/codegen/box/reflection/createAnnotation") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class CreateAnnotation extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInCreateAnnotation() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/createAnnotation"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("arrayOfKClasses.kt") + public void testArrayOfKClasses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/createAnnotation/arrayOfKClasses.kt"); + doTest(fileName); + } + + @TestMetadata("callByKotlin.kt") + public void testCallByKotlin() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/createAnnotation/callByKotlin.kt"); + doTest(fileName); + } + + @TestMetadata("callKotlin.kt") + public void testCallKotlin() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/createAnnotation/callKotlin.kt"); + doTest(fileName); + } + } + @TestMetadata("compiler/testData/codegen/box/reflection/enclosing") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -12614,6 +12647,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/mapping/types"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("annotationConstructorParameters.kt") + public void testAnnotationConstructorParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/mapping/types/annotationConstructorParameters.kt"); + doTest(fileName); + } + @TestMetadata("array.kt") public void testArray() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/mapping/types/array.kt"); diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/AnnotationConstructorCaller.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/AnnotationConstructorCaller.kt new file mode 100644 index 00000000000..1190c36071b --- /dev/null +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/AnnotationConstructorCaller.kt @@ -0,0 +1,95 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.reflect.jvm.internal + +import org.jetbrains.kotlin.load.java.structure.reflect.wrapperByPrimitive +import java.lang.reflect.Proxy +import kotlin.reflect.KClass +import kotlin.reflect.KotlinReflectionInternalError +import java.lang.reflect.Method as ReflectMethod + +internal class AnnotationConstructorCaller( + private val jClass: Class<*>, + private val parameterNames: List, + private val callMode: CallMode, + methods: List = parameterNames.map { name -> jClass.getDeclaredMethod(name) } +) : FunctionCaller( + null, jClass, null, methods.map { it.genericReturnType }.toTypedArray() +) { + enum class CallMode { CALL_BY_NAME, POSITIONAL_CALL } + + // Transform primitive int to java.lang.Integer because actual arguments passed here will be boxed and Class#isInstance should succeed + private val erasedParameterTypes: List> = methods.map { method -> method.returnType.let { it.wrapperByPrimitive ?: it } } + + private val defaultValues: List = methods.map { method -> method.defaultValue } + + override fun call(args: Array<*>): Any? { + checkArguments(args) + + val values = args.mapIndexed { index, arg -> + val value = + if (arg == null && callMode == CallMode.CALL_BY_NAME) defaultValues[index] + else arg.transformKotlinToJvm(erasedParameterTypes[index]) + value ?: throwIllegalArgumentType(index, parameterNames[index], erasedParameterTypes[index]) + } + + return createAnnotationInstance(jClass, parameterNames.zip(values).toMap()) + } +} + +/** + * Transforms a Kotlin value to the one required by the JVM, e.g. KClass<*> -> Class<*> or Array> -> Array>. + * Returns `null` in case when no transformation is possible (an argument of an incorrect type was passed). + */ +private fun Any?.transformKotlinToJvm(expectedType: Class<*>): Any? { + @Suppress("UNCHECKED_CAST") + val result = when (this) { + is Class<*> -> return null + is KClass<*> -> this.java + is Array<*> -> when { + this.isArrayOf>() -> return null + this.isArrayOf>() -> (this as Array>).map(KClass<*>::java).toTypedArray() + else -> this + } + else -> this + } + + return if (expectedType.isInstance(result)) result else null +} + +private fun throwIllegalArgumentType(index: Int, name: String, expectedJvmType: Class<*>): Nothing { + val kotlinClass = when { + expectedJvmType == Class::class.java -> KClass::class + expectedJvmType.isArray && expectedJvmType.componentType == Class::class.java -> + @Suppress("CLASS_LITERAL_LHS_NOT_A_CLASS") Array>::class // Workaround KT-13924 + else -> expectedJvmType.kotlin + } + // For arrays, also render the type argument in the message, e.g. "... not of the required type kotlin.Array" + val typeString = when { + kotlinClass.qualifiedName == Array::class.qualifiedName -> + "${kotlinClass.qualifiedName}<${kotlinClass.java.componentType.kotlin.qualifiedName}>" + else -> kotlinClass.qualifiedName + } + throw IllegalArgumentException("Argument #$index $name is not of the required type $typeString") +} + +private fun createAnnotationInstance(annotationClass: Class<*>, values: Map): Any { + return Proxy.newProxyInstance(annotationClass.classLoader, arrayOf(annotationClass)) { proxy, method, args -> + // TODO: support equals, hashCode, toString, annotationType + values[method.name] ?: throw KotlinReflectionInternalError("Method is not supported: $method (args: ${args.orEmpty().toList()})") + } +} diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt index 502daa64d9e..924d5d6b4f7 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/FunctionCaller.kt @@ -23,7 +23,7 @@ import java.lang.reflect.Constructor as ReflectConstructor import java.lang.reflect.Field as ReflectField import java.lang.reflect.Method as ReflectMethod -internal abstract class FunctionCaller( +internal abstract class FunctionCaller( internal val member: M, internal val returnType: Type, internal val instanceClass: Class<*>?, @@ -45,7 +45,7 @@ internal abstract class FunctionCaller( } protected fun checkObjectInstance(obj: Any?) { - if (obj == null || !member.declaringClass.isInstance(obj)) { + if (obj == null || !member!!.declaringClass.isInstance(obj)) { throw IllegalArgumentException("An object member requires the object instance passed as the first argument.") } } diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt index f4aefbc20f9..9ec892f6286 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt @@ -27,8 +27,10 @@ import kotlin.reflect.jvm.javaType internal abstract class KCallableImpl : KCallable { abstract val descriptor: CallableMemberDescriptor + // The instance which is used to perform a positional call, i.e. `call` abstract val caller: FunctionCaller<*> + // The instance which is used to perform a call "by name", i.e. `callBy` abstract val defaultCaller: FunctionCaller<*>? abstract val container: KDeclarationContainerImpl @@ -94,7 +96,7 @@ internal abstract class KCallableImpl : KCallable { override val isAbstract: Boolean get() = descriptor.modality == Modality.ABSTRACT - private val isAnnotationConstructor: Boolean + protected val isAnnotationConstructor: Boolean get() = name == "" && container.jClass.isAnnotation @Suppress("UNCHECKED_CAST") @@ -102,8 +104,12 @@ internal abstract class KCallableImpl : KCallable { return caller.call(args) as R } - // See ArgumentGenerator#generate override fun callBy(args: Map): R { + return if (isAnnotationConstructor) callAnnotationConstructor(args) else callDefaultMethod(args) + } + + // See ArgumentGenerator#generate + private fun callDefaultMethod(args: Map): R { val parameters = parameters val arguments = ArrayList(parameters.size) var mask = 0 @@ -153,6 +159,25 @@ internal abstract class KCallableImpl : KCallable { } } + private fun callAnnotationConstructor(args: Map): R { + val arguments = parameters.map { parameter -> + when { + args.containsKey(parameter) -> { + args[parameter] ?: throw IllegalArgumentException("Annotation argument value cannot be null ($parameter)") + } + parameter.isOptional -> null + else -> throw IllegalArgumentException("No argument provided for a required parameter: $parameter") + } + } + + val caller = defaultCaller ?: throw KotlinReflectionInternalError("This callable does not support a default call: $descriptor") + + @Suppress("UNCHECKED_CAST") + return reflectionCall { + caller.call(arguments.toTypedArray()) as R + } + } + private fun defaultPrimitiveValue(type: Type): Any? = if (type is Class<*> && type.isPrimitive) { when (type) { diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt index 91b4e6d1810..c0ec584e620 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KClassImpl.kt @@ -170,10 +170,10 @@ internal class KClassImpl(override val jClass: Class) : KDeclaration override val constructorDescriptors: Collection get() { val descriptor = descriptor - if (descriptor.kind == ClassKind.CLASS || descriptor.kind == ClassKind.ENUM_CLASS) { - return descriptor.constructors + if (descriptor.kind == ClassKind.INTERFACE || descriptor.kind == ClassKind.OBJECT) { + return emptyList() } - return emptyList() + return descriptor.constructors } override fun getProperties(name: Name): Collection = diff --git a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt index df1f0b963bf..41e9542880f 100644 --- a/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt +++ b/core/reflection.jvm/src/kotlin/reflect/jvm/internal/KFunctionImpl.kt @@ -26,6 +26,8 @@ import java.lang.reflect.Modifier import kotlin.jvm.internal.FunctionImpl import kotlin.reflect.KFunction import kotlin.reflect.KotlinReflectionInternalError +import kotlin.reflect.jvm.internal.AnnotationConstructorCaller.CallMode.CALL_BY_NAME +import kotlin.reflect.jvm.internal.AnnotationConstructorCaller.CallMode.POSITIONAL_CALL import kotlin.reflect.jvm.internal.JvmFunctionSignature.* internal class KFunctionImpl private constructor( @@ -48,10 +50,14 @@ internal class KFunctionImpl private constructor( private fun isDeclared(): Boolean = Visibilities.isPrivate(descriptor.visibility) - override val caller: FunctionCaller<*> by ReflectProperties.lazySoft { + override val caller: FunctionCaller<*> by ReflectProperties.lazySoft caller@ { val jvmSignature = RuntimeTypeMapper.mapSignature(descriptor) val member: Member? = when (jvmSignature) { - is KotlinConstructor -> container.findConstructorBySignature(jvmSignature.constructorDesc, isDeclared()) + is KotlinConstructor -> { + if (isAnnotationConstructor) + return@caller AnnotationConstructorCaller(container.jClass, parameters.map { it.name!! }, POSITIONAL_CALL) + container.findConstructorBySignature(jvmSignature.constructorDesc, isDeclared()) + } is KotlinFunction -> container.findMethodBySignature(jvmSignature.methodName, jvmSignature.methodDesc, isDeclared()) is JavaMethod -> jvmSignature.method is JavaConstructor -> jvmSignature.constructor @@ -71,14 +77,16 @@ internal class KFunctionImpl private constructor( } } - override val defaultCaller: FunctionCaller<*>? by ReflectProperties.lazySoft { + override val defaultCaller: FunctionCaller<*>? by ReflectProperties.lazySoft defaultCaller@ { val jvmSignature = RuntimeTypeMapper.mapSignature(descriptor) val member: Member? = when (jvmSignature) { is KotlinFunction -> { container.findDefaultMethod(jvmSignature.methodName, jvmSignature.methodDesc, - !Modifier.isStatic(caller.member.modifiers), isDeclared()) + !Modifier.isStatic(caller.member!!.modifiers), isDeclared()) } is KotlinConstructor -> { + if (isAnnotationConstructor) + return@defaultCaller AnnotationConstructorCaller(container.jClass, parameters.map { it.name!! }, CALL_BY_NAME) container.findDefaultConstructor(jvmSignature.constructorDesc, isDeclared()) } else -> {