Implement typeOf intrinsic on JVM
#KT-29915 Fixed
This commit is contained in:
@@ -69,7 +69,8 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
|
||||
private val initialFrameSize = codegen.frameMap.currentSize
|
||||
|
||||
private val reifiedTypeInliner = ReifiedTypeInliner(typeParameterMappings, state.languageVersionSettings.isReleaseCoroutines())
|
||||
private val reifiedTypeInliner =
|
||||
ReifiedTypeInliner(typeParameterMappings, state.typeMapper, state.languageVersionSettings.isReleaseCoroutines())
|
||||
|
||||
protected val functionDescriptor: FunctionDescriptor =
|
||||
if (InlineUtil.isArrayConstructorWithLambda(function))
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.codegen.generateAsCast
|
||||
import org.jetbrains.kotlin.codegen.generateIsCheck
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.intConstant
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -60,9 +61,13 @@ class ReificationArgument(
|
||||
}
|
||||
}
|
||||
|
||||
class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?, private val isReleaseCoroutines: Boolean) {
|
||||
class ReifiedTypeInliner(
|
||||
private val parametersMapping: TypeParameterMappings?,
|
||||
private val typeMapper: KotlinTypeMapper,
|
||||
private val isReleaseCoroutines: Boolean
|
||||
) {
|
||||
enum class OperationKind {
|
||||
NEW_ARRAY, AS, SAFE_AS, IS, JAVA_CLASS, ENUM_REIFIED;
|
||||
NEW_ARRAY, AS, SAFE_AS, IS, JAVA_CLASS, ENUM_REIFIED, TYPE_OF;
|
||||
|
||||
val id: Int get() = ordinal
|
||||
}
|
||||
@@ -143,6 +148,7 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?,
|
||||
OperationKind.IS -> processIs(insn, instructions, kotlinType, asmType)
|
||||
OperationKind.JAVA_CLASS -> processJavaClass(insn, asmType)
|
||||
OperationKind.ENUM_REIFIED -> processSpecialEnumFunction(insn, instructions, asmType)
|
||||
OperationKind.TYPE_OF -> processTypeOf(insn, instructions, kotlinType)
|
||||
}
|
||||
) {
|
||||
instructions.remove(insn.previous.previous!!) // PUSH operation ID
|
||||
@@ -201,6 +207,21 @@ class ReifiedTypeInliner(private val parametersMapping: TypeParameterMappings?,
|
||||
return true
|
||||
}
|
||||
|
||||
private fun processTypeOf(
|
||||
insn: MethodInsnNode,
|
||||
instructions: InsnList,
|
||||
kotlinType: KotlinType
|
||||
) = rewriteNextTypeInsn(insn, Opcodes.ACONST_NULL) { stubConstNull: AbstractInsnNode ->
|
||||
val newMethodNode = MethodNode(Opcodes.API_VERSION)
|
||||
val stackSize = generateTypeOf(InstructionAdapter(newMethodNode), kotlinType, typeMapper)
|
||||
|
||||
instructions.insert(insn, newMethodNode.instructions)
|
||||
instructions.remove(stubConstNull)
|
||||
|
||||
maxStackSize = Math.max(maxStackSize, stackSize)
|
||||
return true
|
||||
}
|
||||
|
||||
inline private fun rewriteNextTypeInsn(
|
||||
marker: MethodInsnNode,
|
||||
expectedNextOpcode: Int,
|
||||
|
||||
@@ -20,9 +20,13 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.TypeOfChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.isBuiltInCoroutineContext
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeProjection
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
@@ -38,6 +42,8 @@ internal fun generateInlineIntrinsic(
|
||||
return when {
|
||||
isSpecialEnumMethod(descriptor) ->
|
||||
createSpecialEnumMethodBody(descriptor.name.asString(), typeArguments!!.keys.single().defaultType, typeMapper)
|
||||
TypeOfChecker.isTypeOf(descriptor) ->
|
||||
createTypeOfMethodBody(typeArguments!!.keys.single().defaultType)
|
||||
descriptor.isBuiltInIntercepted(languageVersionSettings) ->
|
||||
createMethodNodeForIntercepted(descriptor, typeMapper, languageVersionSettings)
|
||||
descriptor.isBuiltInCoroutineContext(languageVersionSettings) ->
|
||||
@@ -94,3 +100,101 @@ private fun createSpecialEnumMethodBody(name: String, type: KotlinType, typeMapp
|
||||
internal fun getSpecialEnumFunDescriptor(type: Type, isValueOf: Boolean): String =
|
||||
if (isValueOf) Type.getMethodDescriptor(type, JAVA_STRING_TYPE)
|
||||
else Type.getMethodDescriptor(AsmUtil.getArrayType(type))
|
||||
|
||||
private fun createTypeOfMethodBody(type: KotlinType): MethodNode {
|
||||
val node = MethodNode(Opcodes.API_VERSION, Opcodes.ACC_STATIC, "fake", Type.getMethodDescriptor(K_TYPE), null, null)
|
||||
val v = InstructionAdapter(node)
|
||||
|
||||
putTypeOfReifiedTypeParameter(v, type)
|
||||
v.areturn(K_TYPE)
|
||||
|
||||
v.visitMaxs(2, 0)
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
private fun putTypeOfReifiedTypeParameter(v: InstructionAdapter, type: KotlinType) {
|
||||
ExpressionCodegen.putReifiedOperationMarkerIfTypeIsReifiedParameterWithoutPropagation(type, ReifiedTypeInliner.OperationKind.TYPE_OF, v)
|
||||
v.aconst(null)
|
||||
}
|
||||
|
||||
// Returns some upper bound on maximum stack size
|
||||
internal fun generateTypeOf(v: InstructionAdapter, kotlinType: KotlinType, typeMapper: KotlinTypeMapper): Int {
|
||||
val asmType = typeMapper.mapType(kotlinType)
|
||||
AsmUtil.putJavaLangClassInstance(v, asmType, kotlinType, typeMapper)
|
||||
|
||||
val arguments = kotlinType.arguments
|
||||
val useArray = arguments.size >= 3
|
||||
|
||||
if (useArray) {
|
||||
v.iconst(arguments.size)
|
||||
v.newarray(K_TYPE_PROJECTION)
|
||||
}
|
||||
|
||||
var maxStackSize = 3
|
||||
|
||||
for (i in 0 until arguments.size) {
|
||||
if (useArray) {
|
||||
v.dup()
|
||||
v.iconst(i)
|
||||
}
|
||||
|
||||
val stackSize = doGenerateTypeProjection(v, arguments[i], typeMapper)
|
||||
maxStackSize = maxOf(maxStackSize, stackSize + i + 5)
|
||||
|
||||
if (useArray) {
|
||||
v.astore(K_TYPE_PROJECTION)
|
||||
}
|
||||
}
|
||||
|
||||
val methodName = if (kotlinType.isMarkedNullable) "nullableTypeOf" else "typeOf"
|
||||
|
||||
val projections = when (arguments.size) {
|
||||
0 -> emptyArray()
|
||||
1 -> arrayOf(K_TYPE_PROJECTION)
|
||||
2 -> arrayOf(K_TYPE_PROJECTION, K_TYPE_PROJECTION)
|
||||
else -> arrayOf(AsmUtil.getArrayType(K_TYPE_PROJECTION))
|
||||
}
|
||||
val signature = Type.getMethodDescriptor(K_TYPE, JAVA_CLASS_TYPE, *projections)
|
||||
|
||||
v.invokestatic(REFLECTION, methodName, signature, false)
|
||||
|
||||
return maxStackSize
|
||||
}
|
||||
|
||||
private fun doGenerateTypeProjection(
|
||||
v: InstructionAdapter,
|
||||
projection: TypeProjection,
|
||||
typeMapper: KotlinTypeMapper
|
||||
): Int {
|
||||
// KTypeProjection members could be static, see KT-30083 and KT-30084
|
||||
v.getstatic(K_TYPE_PROJECTION.internalName, "Companion", K_TYPE_PROJECTION_COMPANION.descriptor)
|
||||
|
||||
if (projection.isStarProjection) {
|
||||
v.invokevirtual(K_TYPE_PROJECTION_COMPANION.internalName, "getSTAR", Type.getMethodDescriptor(K_TYPE_PROJECTION), false)
|
||||
return 1
|
||||
}
|
||||
|
||||
val type = projection.type
|
||||
val descriptor = type.constructor.declarationDescriptor
|
||||
val stackSize = if (descriptor is TypeParameterDescriptor) {
|
||||
if (descriptor.isReified) {
|
||||
putTypeOfReifiedTypeParameter(v, type)
|
||||
2
|
||||
} else {
|
||||
// TODO: support non-reified type parameters in typeOf
|
||||
generateTypeOf(v, type.builtIns.nullableAnyType, typeMapper)
|
||||
}
|
||||
} else {
|
||||
generateTypeOf(v, type, typeMapper)
|
||||
}
|
||||
|
||||
val methodName = when (projection.projectionKind) {
|
||||
Variance.INVARIANT -> "invariant"
|
||||
Variance.IN_VARIANCE -> "contravariant"
|
||||
Variance.OUT_VARIANCE -> "covariant"
|
||||
}
|
||||
v.invokevirtual(K_TYPE_PROJECTION_COMPANION.internalName, methodName, Type.getMethodDescriptor(K_TYPE_PROJECTION, K_TYPE), false)
|
||||
|
||||
return stackSize + 1
|
||||
}
|
||||
|
||||
@@ -63,6 +63,10 @@ public class AsmTypes {
|
||||
public static final Type K_MUTABLE_PROPERTY1_TYPE = reflect("KMutableProperty1");
|
||||
public static final Type K_MUTABLE_PROPERTY2_TYPE = reflect("KMutableProperty2");
|
||||
|
||||
public static final Type K_TYPE = reflect("KType");
|
||||
public static final Type K_TYPE_PROJECTION = reflect("KTypeProjection");
|
||||
public static final Type K_TYPE_PROJECTION_COMPANION = reflect("KTypeProjection$Companion");
|
||||
|
||||
public static final Type SUSPEND_FUNCTION_TYPE = Type.getObjectType("kotlin/coroutines/jvm/internal/SuspendFunction");
|
||||
|
||||
public static final String REFLECTION = "kotlin/jvm/internal/Reflection";
|
||||
|
||||
@@ -45,7 +45,7 @@ private val DEFAULT_CALL_CHECKERS = listOf(
|
||||
UnderscoreUsageChecker, AssigningNamedArgumentToVarargChecker(),
|
||||
PrimitiveNumericComparisonCallChecker, LambdaWithSuspendModifierCallChecker,
|
||||
UselessElvisCallChecker(), ResultTypeWithNullableOperatorsChecker(), NullableVarargArgumentCallChecker,
|
||||
NamedFunAsExpressionChecker, ContractNotAllowedCallChecker, ReifiedTypeParameterSubstitutionChecker()
|
||||
NamedFunAsExpressionChecker, ContractNotAllowedCallChecker, ReifiedTypeParameterSubstitutionChecker(), TypeOfChecker
|
||||
)
|
||||
private val DEFAULT_TYPE_CHECKERS = emptyList<AdditionalTypeChecker>()
|
||||
private val DEFAULT_CLASSIFIER_USAGE_CHECKERS = listOf(
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. 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.resolve.calls.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.builtins.KOTLIN_REFLECT_FQ_NAME
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.types.typeUtil.contains
|
||||
|
||||
object TypeOfChecker : CallChecker {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
if (!isTypeOf(resolvedCall.resultingDescriptor)) return
|
||||
|
||||
for ((_, argument) in resolvedCall.typeArguments) {
|
||||
if (argument.contains { type ->
|
||||
val descriptor = type.constructor.declarationDescriptor
|
||||
descriptor is TypeParameterDescriptor && !descriptor.isReified
|
||||
}) {
|
||||
context.trace.report(Errors.UNSUPPORTED.on(reportOn, "'typeOf' with non-reified type parameters is not supported"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isTypeOf(descriptor: CallableDescriptor): Boolean =
|
||||
descriptor.name.asString() == "typeOf" &&
|
||||
descriptor.valueParameters.isEmpty() &&
|
||||
(descriptor.containingDeclaration as? PackageFragmentDescriptor)?.fqName == KOTLIN_REFLECT_FQ_NAME
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// IGNORE_BACKEND: JS, JS_IR, NATIVE
|
||||
// WITH_REFLECT
|
||||
|
||||
package test
|
||||
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class C
|
||||
|
||||
fun check(expected: String, actual: KType) {
|
||||
assertEquals(expected, actual.toString())
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
check("kotlin.Any", typeOf<Any>())
|
||||
check("kotlin.String", typeOf<String>())
|
||||
check("kotlin.String?", typeOf<String?>())
|
||||
check("kotlin.Unit", typeOf<Unit>())
|
||||
|
||||
check("test.C", typeOf<C>())
|
||||
check("test.C?", typeOf<C?>())
|
||||
|
||||
check("kotlin.collections.List<kotlin.String>", typeOf<List<String>>())
|
||||
check("kotlin.collections.Map<in kotlin.Number, kotlin.Any?>?", typeOf<Map<in Number, *>?>())
|
||||
check("kotlin.Enum<out kotlin.Enum<*>>", typeOf<Enum<*>>())
|
||||
check("kotlin.Enum<kotlin.annotation.AnnotationRetention>", typeOf<Enum<AnnotationRetention>>())
|
||||
|
||||
check("kotlin.Array<kotlin.Any>", typeOf<Array<Any>>())
|
||||
check("kotlin.Array<out kotlin.Any?>", typeOf<Array<*>>())
|
||||
check("kotlin.Array<kotlin.IntArray>", typeOf<Array<IntArray>>())
|
||||
check("kotlin.Array<in kotlin.Array<test.C>?>", typeOf<Array<in Array<C>?>>())
|
||||
|
||||
check("kotlin.Int", typeOf<Int>())
|
||||
check("kotlin.Int?", typeOf<Int?>())
|
||||
check("kotlin.Boolean", typeOf<Boolean>())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// IGNORE_BACKEND: JVM_IR, JS, JS_IR, NATIVE
|
||||
// WITH_REFLECT
|
||||
|
||||
package test
|
||||
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
inline class Z(val value: String)
|
||||
|
||||
fun check(expected: String, actual: KType) {
|
||||
assertEquals(expected, actual.toString())
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
check("test.Z", typeOf<Z>())
|
||||
check("test.Z?", typeOf<Z?>())
|
||||
check("kotlin.Array<test.Z>", typeOf<Array<Z>>())
|
||||
check("kotlin.Array<test.Z?>", typeOf<Array<Z?>>())
|
||||
|
||||
check("kotlin.UInt", typeOf<UInt>())
|
||||
check("kotlin.UInt?", typeOf<UInt?>())
|
||||
check("kotlin.ULong?", typeOf<ULong?>())
|
||||
check("kotlin.UShortArray", typeOf<UShortArray>())
|
||||
check("kotlin.UShortArray?", typeOf<UShortArray?>())
|
||||
check("kotlin.Array<kotlin.UByteArray>", typeOf<Array<UByteArray>>())
|
||||
check("kotlin.Array<kotlin.UByteArray?>?", typeOf<Array<UByteArray?>?>())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// IGNORE_BACKEND: JS, JS_IR, NATIVE
|
||||
// WITH_REFLECT
|
||||
|
||||
package test
|
||||
|
||||
import kotlin.reflect.typeOf
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
interface I1
|
||||
interface I2
|
||||
interface I3
|
||||
interface I4
|
||||
interface I5
|
||||
interface I6
|
||||
interface I7
|
||||
|
||||
class C<T1, T2, T3, T4, T5, T6, T7>
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(
|
||||
"test.C<test.I1, test.I2, test.I3?, in test.I4, out test.I5, test.I6, test.I7?>",
|
||||
typeOf<C<I1, I2, I3?, in I4, out I5, I6, I7?>>().toString()
|
||||
)
|
||||
assertEquals(
|
||||
"test.C<out test.I1, test.I2?, test.I3, test.I4, test.I5, test.I6?, in test.I7>?",
|
||||
typeOf<C<out I1, I2?, I3, I4, I5, I6?, in I7>?>().toString()
|
||||
)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// IGNORE_BACKEND: JS, JS_IR, NATIVE
|
||||
// WITH_REFLECT
|
||||
|
||||
package test
|
||||
|
||||
import kotlin.reflect.typeOf
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
interface C
|
||||
|
||||
inline fun <reified T> get() = typeOf<T>()
|
||||
|
||||
inline fun <reified U> get1() = get<U?>()
|
||||
|
||||
inline fun <reified V> get2() = get1<Map<in V?, Array<V>>>()
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("kotlin.collections.Map<in test.C?, kotlin.Array<test.C>>?", get2<C>().toString())
|
||||
assertEquals("kotlin.collections.Map<in kotlin.collections.List<test.C>?, kotlin.Array<kotlin.collections.List<test.C>>>?", get2<List<C>>().toString())
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
package test
|
||||
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class C
|
||||
|
||||
fun check(expected: String, actual: KType) {
|
||||
assertEquals(expected + " (Kotlin reflection is not available)", actual.toString())
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
check("java.lang.Object", typeOf<Any>())
|
||||
check("java.lang.String", typeOf<String>())
|
||||
check("java.lang.String?", typeOf<String?>())
|
||||
check("kotlin.Unit", typeOf<Unit>())
|
||||
|
||||
check("test.C", typeOf<C>())
|
||||
check("test.C?", typeOf<C?>())
|
||||
|
||||
check("java.util.List<java.lang.String>", typeOf<List<String>>())
|
||||
check("java.util.Map<in java.lang.Number, java.lang.Object?>?", typeOf<Map<in Number, *>?>())
|
||||
check("java.lang.Enum<out java.lang.Enum<*>>", typeOf<Enum<*>>())
|
||||
check("java.lang.Enum<kotlin.annotation.AnnotationRetention>", typeOf<Enum<AnnotationRetention>>())
|
||||
|
||||
check("kotlin.Array<java.lang.Object>", typeOf<Array<Any>>())
|
||||
check("kotlin.Array<out java.lang.Object?>", typeOf<Array<*>>())
|
||||
check("kotlin.Array<kotlin.IntArray>", typeOf<Array<IntArray>>())
|
||||
check("kotlin.Array<in kotlin.Array<test.C>?>", typeOf<Array<in Array<C>?>>())
|
||||
|
||||
check("int", typeOf<Int>())
|
||||
check("java.lang.Integer?", typeOf<Int?>())
|
||||
check("boolean", typeOf<Boolean>())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
|
||||
package test
|
||||
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
inline class Z(val value: String)
|
||||
|
||||
fun check(expected: String, actual: KType) {
|
||||
assertEquals(expected + " (Kotlin reflection is not available)", actual.toString())
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
check("test.Z", typeOf<Z>())
|
||||
check("test.Z?", typeOf<Z?>())
|
||||
check("kotlin.Array<test.Z>", typeOf<Array<Z>>())
|
||||
check("kotlin.Array<test.Z?>", typeOf<Array<Z?>>())
|
||||
|
||||
check("kotlin.UInt", typeOf<UInt>())
|
||||
check("kotlin.UInt?", typeOf<UInt?>())
|
||||
check("kotlin.ULong?", typeOf<ULong?>())
|
||||
check("kotlin.UShortArray", typeOf<UShortArray>())
|
||||
check("kotlin.UShortArray?", typeOf<UShortArray?>())
|
||||
check("kotlin.Array<kotlin.UByteArray>", typeOf<Array<UByteArray>>())
|
||||
check("kotlin.Array<kotlin.UByteArray?>?", typeOf<Array<UByteArray?>?>())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
package test
|
||||
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
class C
|
||||
|
||||
fun assertEqual(a: KType, b: KType) {
|
||||
if (a != b || b != a) throw AssertionError("Fail equals: $a != $b")
|
||||
if (a.hashCode() != b.hashCode()) throw AssertionError("Fail hashCode: $a != $b")
|
||||
}
|
||||
|
||||
fun assertNotEqual(a: KType, b: KType) {
|
||||
if (a == b || b == a) throw AssertionError("Fail equals: $a == $b")
|
||||
}
|
||||
|
||||
inline fun <reified A, reified B> equal() {
|
||||
assertEqual(typeOf<A>(), typeOf<B>())
|
||||
}
|
||||
|
||||
inline fun <reified A, reified B> notEqual() {
|
||||
assertNotEqual(typeOf<A>(), typeOf<B>())
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
equal<Any, Any>()
|
||||
equal<Any?, Any?>()
|
||||
equal<String, String>()
|
||||
|
||||
equal<C, C>()
|
||||
equal<C?, C?>()
|
||||
|
||||
equal<List<String>, List<String>>()
|
||||
equal<Enum<AnnotationRetention>, Enum<AnnotationRetention>>()
|
||||
|
||||
equal<Array<Any>, Array<Any>>()
|
||||
equal<Array<IntArray>, Array<IntArray>>()
|
||||
equal<Array<*>, Array<out Any?>>() // This is subject to change if we retain star projections in typeOf
|
||||
|
||||
equal<Int, Int>()
|
||||
equal<Int?, Int?>()
|
||||
|
||||
notEqual<Any, Any?>()
|
||||
notEqual<Any, String>()
|
||||
notEqual<List<Any>, List<Any?>>()
|
||||
notEqual<Map<in Number, BooleanArray>, Map<out Number, BooleanArray>>()
|
||||
notEqual<Array<IntArray>, Array<Array<Int>>>()
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
|
||||
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
inline fun <X, reified Y, Z : Y> test1() {
|
||||
<!UNSUPPORTED!>typeOf<!><<!TYPE_PARAMETER_AS_REIFIED!>X<!>>()
|
||||
<!UNSUPPORTED!>typeOf<!><List<X>>()
|
||||
<!UNSUPPORTED!>typeOf<!><Array<X?>>()
|
||||
|
||||
typeOf<Y>()
|
||||
|
||||
<!UNSUPPORTED!>typeOf<!><<!TYPE_PARAMETER_AS_REIFIED!>Z<!>>()
|
||||
<!UNSUPPORTED!>typeOf<!><List<Z>?>()
|
||||
<!UNSUPPORTED!>typeOf<!><Array<Z>>()
|
||||
}
|
||||
|
||||
|
||||
class Test2<W> {
|
||||
fun test2() {
|
||||
<!UNSUPPORTED!>typeOf<!><<!TYPE_PARAMETER_AS_REIFIED!>W<!>>()
|
||||
<!UNSUPPORTED!>typeOf<!><List<W?>>()
|
||||
<!UNSUPPORTED!>typeOf<!><Array<W>>()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline fun <reified U> f() {
|
||||
typeOf<U>()
|
||||
}
|
||||
|
||||
fun <T> test3() {
|
||||
// We don't report anything here because we can't know in frontend how the corresponding type parameter is used in f
|
||||
f<List<T>>()
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package
|
||||
|
||||
public inline fun </*0*/ reified U> f(): kotlin.Unit
|
||||
public inline fun </*0*/ X, /*1*/ reified Y, /*2*/ Z : Y> test1(): kotlin.Unit
|
||||
public fun </*0*/ T> test3(): kotlin.Unit
|
||||
|
||||
public final class Test2</*0*/ W> {
|
||||
public constructor Test2</*0*/ W>()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final fun test2(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+18
@@ -2941,6 +2941,24 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/reflection")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Reflection extends AbstractDiagnosticsTestWithStdLib {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInReflection() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/reflection"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("typeOfWithNonReifiedParameter.kt")
|
||||
public void testTypeOfWithNonReifiedParameter() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/reflection/typeOfWithNonReifiedParameter.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/regression")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java
Generated
+18
@@ -2941,6 +2941,24 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/reflection")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Reflection extends AbstractDiagnosticsTestWithStdLibUsingJavac {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInReflection() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testsWithStdLib/reflection"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("typeOfWithNonReifiedParameter.kt")
|
||||
public void testTypeOfWithNonReifiedParameter() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/reflection/typeOfWithNonReifiedParameter.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/regression")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+61
@@ -21487,6 +21487,67 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class TypeOf extends AbstractBlackBoxCodegenTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInTypeOf() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classes.kt")
|
||||
public void testClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/classes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClasses.kt")
|
||||
public void testInlineClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/inlineClasses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("manyTypeArguments.kt")
|
||||
public void testManyTypeArguments() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/manyTypeArguments.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multipleLayers.kt")
|
||||
public void testMultipleLayers() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/noReflect")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class NoReflect extends AbstractBlackBoxCodegenTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInNoReflect() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf/noReflect"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classes.kt")
|
||||
public void testClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClasses.kt")
|
||||
public void testInlineClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/inlineClasses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeReferenceEqualsHashCode.kt")
|
||||
public void testTypeReferenceEqualsHashCode() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCode.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeParameters")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+61
@@ -21487,6 +21487,67 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class TypeOf extends AbstractLightAnalysisModeTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInTypeOf() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classes.kt")
|
||||
public void testClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/classes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClasses.kt")
|
||||
public void testInlineClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/inlineClasses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("manyTypeArguments.kt")
|
||||
public void testManyTypeArguments() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/manyTypeArguments.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multipleLayers.kt")
|
||||
public void testMultipleLayers() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/noReflect")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class NoReflect extends AbstractLightAnalysisModeTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInNoReflect() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf/noReflect"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classes.kt")
|
||||
public void testClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClasses.kt")
|
||||
public void testInlineClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/inlineClasses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeReferenceEqualsHashCode.kt")
|
||||
public void testTypeReferenceEqualsHashCode() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCode.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeParameters")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+61
@@ -21492,6 +21492,67 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class TypeOf extends AbstractIrBlackBoxCodegenTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInTypeOf() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classes.kt")
|
||||
public void testClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/classes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClasses.kt")
|
||||
public void testInlineClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/inlineClasses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("manyTypeArguments.kt")
|
||||
public void testManyTypeArguments() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/manyTypeArguments.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multipleLayers.kt")
|
||||
public void testMultipleLayers() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/noReflect")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class NoReflect extends AbstractIrBlackBoxCodegenTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInNoReflect() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf/noReflect"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classes.kt")
|
||||
public void testClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClasses.kt")
|
||||
public void testInlineClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/inlineClasses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("typeReferenceEqualsHashCode.kt")
|
||||
public void testTypeReferenceEqualsHashCode() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCode.kt");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeParameters")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -18,8 +18,13 @@ package kotlin.reflect.jvm.internal;
|
||||
|
||||
import kotlin.jvm.internal.*;
|
||||
import kotlin.reflect.*;
|
||||
import kotlin.reflect.full.KClassifiers;
|
||||
import kotlin.reflect.jvm.ReflectLambdaKt;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @suppress
|
||||
*/
|
||||
@@ -111,6 +116,13 @@ public class ReflectionFactoryImpl extends ReflectionFactory {
|
||||
return owner instanceof KDeclarationContainerImpl ? ((KDeclarationContainerImpl) owner) : EmptyContainerForLocal.INSTANCE;
|
||||
}
|
||||
|
||||
// typeOf
|
||||
|
||||
@Override
|
||||
public KType typeOf(KClassifier klass, List<KTypeProjection> arguments, boolean isMarkedNullable) {
|
||||
return KClassifiers.createType(klass, arguments, isMarkedNullable, Collections.<Annotation>emptyList());
|
||||
}
|
||||
|
||||
// Misc
|
||||
|
||||
public static void clearCaches() {
|
||||
|
||||
+46
@@ -16587,6 +16587,52 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class TypeOf extends AbstractIrJsCodegenBoxTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInTypeOf() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classes.kt")
|
||||
public void testClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/classes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClasses.kt")
|
||||
public void testInlineClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/inlineClasses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("manyTypeArguments.kt")
|
||||
public void testManyTypeArguments() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/manyTypeArguments.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multipleLayers.kt")
|
||||
public void testMultipleLayers() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/noReflect")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class NoReflect extends AbstractIrJsCodegenBoxTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInNoReflect() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf/noReflect"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeParameters")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+46
@@ -17682,6 +17682,52 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class TypeOf extends AbstractJsCodegenBoxTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInTypeOf() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("classes.kt")
|
||||
public void testClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/classes.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClasses.kt")
|
||||
public void testInlineClasses() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/inlineClasses.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("manyTypeArguments.kt")
|
||||
public void testManyTypeArguments() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/manyTypeArguments.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multipleLayers.kt")
|
||||
public void testMultipleLayers() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/noReflect")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class NoReflect extends AbstractJsCodegenBoxTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInNoReflect() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf/noReflect"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/typeParameters")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
@@ -6,8 +6,12 @@
|
||||
package kotlin.jvm.internal;
|
||||
|
||||
import kotlin.SinceKotlin;
|
||||
import kotlin.collections.ArraysKt;
|
||||
import kotlin.reflect.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* This class serves as a facade to the actual reflection implementation. JVM back-end generates calls to static methods of this class
|
||||
* on any reflection-using construct.
|
||||
@@ -105,4 +109,46 @@ public class Reflection {
|
||||
public static KMutableProperty2 mutableProperty2(MutablePropertyReference2 p) {
|
||||
return factory.mutableProperty2(p);
|
||||
}
|
||||
|
||||
// typeOf
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static KType typeOf(Class klass) {
|
||||
return factory.typeOf(getOrCreateKotlinClass(klass), Collections.<KTypeProjection>emptyList(), false);
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static KType typeOf(Class klass, KTypeProjection arg1) {
|
||||
return factory.typeOf(getOrCreateKotlinClass(klass), Collections.singletonList(arg1), false);
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static KType typeOf(Class klass, KTypeProjection arg1, KTypeProjection arg2) {
|
||||
return factory.typeOf(getOrCreateKotlinClass(klass), Arrays.asList(arg1, arg2), false);
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static KType typeOf(Class klass, KTypeProjection... arguments) {
|
||||
return factory.typeOf(getOrCreateKotlinClass(klass), ArraysKt.<KTypeProjection>toList(arguments), false);
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static KType nullableTypeOf(Class klass) {
|
||||
return factory.typeOf(getOrCreateKotlinClass(klass), Collections.<KTypeProjection>emptyList(), true);
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static KType nullableTypeOf(Class klass, KTypeProjection arg1) {
|
||||
return factory.typeOf(getOrCreateKotlinClass(klass), Collections.singletonList(arg1), true);
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static KType nullableTypeOf(Class klass, KTypeProjection arg1, KTypeProjection arg2) {
|
||||
return factory.typeOf(getOrCreateKotlinClass(klass), Arrays.asList(arg1, arg2), true);
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static KType nullableTypeOf(Class klass, KTypeProjection... arguments) {
|
||||
return factory.typeOf(getOrCreateKotlinClass(klass), ArraysKt.<KTypeProjection>toList(arguments), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ package kotlin.jvm.internal;
|
||||
import kotlin.SinceKotlin;
|
||||
import kotlin.reflect.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ReflectionFactory {
|
||||
private static final String KOTLIN_JVM_FUNCTIONS = "kotlin.jvm.functions.";
|
||||
|
||||
@@ -73,4 +75,11 @@ public class ReflectionFactory {
|
||||
public KMutableProperty2 mutableProperty2(MutablePropertyReference2 p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
// typeOf
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public KType typeOf(KClassifier klass, List<KTypeProjection> arguments, boolean isMarkedNullable) {
|
||||
return new TypeReference(klass, arguments, isMarkedNullable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.jvm.internal
|
||||
|
||||
import kotlin.reflect.*
|
||||
|
||||
@SinceKotlin("1.4")
|
||||
@Suppress("NEWER_VERSION_IN_SINCE_KOTLIN", "API_NOT_AVAILABLE" /* See KT-30129 */) // TODO: remove this in 1.4
|
||||
public class TypeReference(
|
||||
override val classifier: KClassifier,
|
||||
override val arguments: List<KTypeProjection>,
|
||||
override val isMarkedNullable: Boolean
|
||||
) : KType {
|
||||
override val annotations: List<Annotation>
|
||||
get() = emptyList()
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is TypeReference &&
|
||||
classifier == other.classifier && arguments == other.arguments && isMarkedNullable == other.isMarkedNullable
|
||||
|
||||
override fun hashCode(): Int =
|
||||
(classifier.hashCode() * 31 + arguments.hashCode()) * 31 + isMarkedNullable.hashCode()
|
||||
|
||||
override fun toString(): String =
|
||||
asString() + Reflection.REFLECTION_NOT_AVAILABLE
|
||||
|
||||
private fun asString(): String {
|
||||
val javaClass = (classifier as? KClass<*>)?.java
|
||||
val klass = when {
|
||||
javaClass == null -> classifier.toString()
|
||||
javaClass.isArray -> javaClass.arrayClassName
|
||||
else -> javaClass.name
|
||||
}
|
||||
val args =
|
||||
if (arguments.isEmpty()) ""
|
||||
else arguments.joinToString(", ", "<", ">") { it.asString() }
|
||||
val nullable = if (isMarkedNullable) "?" else ""
|
||||
|
||||
return klass + args + nullable
|
||||
}
|
||||
|
||||
private val Class<*>.arrayClassName
|
||||
get() = when (this) {
|
||||
BooleanArray::class.java -> "kotlin.BooleanArray"
|
||||
CharArray::class.java -> "kotlin.CharArray"
|
||||
ByteArray::class.java -> "kotlin.ByteArray"
|
||||
ShortArray::class.java -> "kotlin.ShortArray"
|
||||
IntArray::class.java -> "kotlin.IntArray"
|
||||
FloatArray::class.java -> "kotlin.FloatArray"
|
||||
LongArray::class.java -> "kotlin.LongArray"
|
||||
DoubleArray::class.java -> "kotlin.DoubleArray"
|
||||
else -> "kotlin.Array"
|
||||
}
|
||||
|
||||
// TODO: this should be the implementation of KTypeProjection.toString, see KT-30071
|
||||
@Suppress("NO_REFLECTION_IN_CLASS_PATH")
|
||||
private fun KTypeProjection.asString(): String {
|
||||
if (variance == null) return "*"
|
||||
|
||||
val typeString = (type as? TypeReference)?.asString() ?: type.toString()
|
||||
return when (variance) {
|
||||
KVariance.INVARIANT -> typeString
|
||||
KVariance.IN -> "in $typeString"
|
||||
KVariance.OUT -> "out $typeString"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.reflect
|
||||
|
||||
@Suppress("unused") // KT-12448
|
||||
@SinceKotlin("1.3")
|
||||
@ExperimentalStdlibApi
|
||||
public inline fun <reified T> typeOf(): KType =
|
||||
throw UnsupportedOperationException("This function is implemented as an intrinsic on all supported platforms.")
|
||||
+20
@@ -3531,11 +3531,19 @@ public class kotlin/jvm/internal/Reflection {
|
||||
public static fun mutableProperty0 (Lkotlin/jvm/internal/MutablePropertyReference0;)Lkotlin/reflect/KMutableProperty0;
|
||||
public static fun mutableProperty1 (Lkotlin/jvm/internal/MutablePropertyReference1;)Lkotlin/reflect/KMutableProperty1;
|
||||
public static fun mutableProperty2 (Lkotlin/jvm/internal/MutablePropertyReference2;)Lkotlin/reflect/KMutableProperty2;
|
||||
public static fun nullableTypeOf (Ljava/lang/Class;)Lkotlin/reflect/KType;
|
||||
public static fun nullableTypeOf (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;
|
||||
public static fun nullableTypeOf (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;
|
||||
public static fun nullableTypeOf (Ljava/lang/Class;[Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;
|
||||
public static fun property0 (Lkotlin/jvm/internal/PropertyReference0;)Lkotlin/reflect/KProperty0;
|
||||
public static fun property1 (Lkotlin/jvm/internal/PropertyReference1;)Lkotlin/reflect/KProperty1;
|
||||
public static fun property2 (Lkotlin/jvm/internal/PropertyReference2;)Lkotlin/reflect/KProperty2;
|
||||
public static fun renderLambdaToString (Lkotlin/jvm/internal/FunctionBase;)Ljava/lang/String;
|
||||
public static fun renderLambdaToString (Lkotlin/jvm/internal/Lambda;)Ljava/lang/String;
|
||||
public static fun typeOf (Ljava/lang/Class;)Lkotlin/reflect/KType;
|
||||
public static fun typeOf (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;
|
||||
public static fun typeOf (Ljava/lang/Class;Lkotlin/reflect/KTypeProjection;Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;
|
||||
public static fun typeOf (Ljava/lang/Class;[Lkotlin/reflect/KTypeProjection;)Lkotlin/reflect/KType;
|
||||
}
|
||||
|
||||
public class kotlin/jvm/internal/ReflectionFactory {
|
||||
@@ -3554,6 +3562,7 @@ public class kotlin/jvm/internal/ReflectionFactory {
|
||||
public fun property2 (Lkotlin/jvm/internal/PropertyReference2;)Lkotlin/reflect/KProperty2;
|
||||
public fun renderLambdaToString (Lkotlin/jvm/internal/FunctionBase;)Ljava/lang/String;
|
||||
public fun renderLambdaToString (Lkotlin/jvm/internal/Lambda;)Ljava/lang/String;
|
||||
public fun typeOf (Lkotlin/reflect/KClassifier;Ljava/util/List;Z)Lkotlin/reflect/KType;
|
||||
}
|
||||
|
||||
public final class kotlin/jvm/internal/ShortCompanionObject {
|
||||
@@ -3626,6 +3635,17 @@ public class kotlin/jvm/internal/TypeIntrinsics {
|
||||
public static fun throwCce (Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public final class kotlin/jvm/internal/TypeReference : kotlin/reflect/KType {
|
||||
public fun <init> (Lkotlin/reflect/KClassifier;Ljava/util/List;Z)V
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun getAnnotations ()Ljava/util/List;
|
||||
public fun getArguments ()Ljava/util/List;
|
||||
public fun getClassifier ()Lkotlin/reflect/KClassifier;
|
||||
public fun hashCode ()I
|
||||
public fun isMarkedNullable ()Z
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public abstract interface class kotlin/jvm/internal/markers/KMappedMarker {
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user