Support non-reified type parameters in typeOf in JVM and JVM_IR
#KT-30279 Fixed
This commit is contained in:
committed by
Alexander Udalov
parent
6fb40878c4
commit
0ce16b9d8c
@@ -16,7 +16,7 @@ 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.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
@SuppressWarnings({"unused", "rawtypes"})
|
||||
public class Reflection {
|
||||
private static final ReflectionFactory factory;
|
||||
|
||||
@@ -117,6 +117,11 @@ public class Reflection {
|
||||
|
||||
// typeOf
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static KType typeOf(KClassifier classifier) {
|
||||
return factory.typeOf(classifier, Collections.<KTypeProjection>emptyList(), false);
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static KType typeOf(Class klass) {
|
||||
return factory.typeOf(getOrCreateKotlinClass(klass), Collections.<KTypeProjection>emptyList(), false);
|
||||
@@ -137,6 +142,11 @@ public class Reflection {
|
||||
return factory.typeOf(getOrCreateKotlinClass(klass), ArraysKt.<KTypeProjection>toList(arguments), false);
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static KType nullableTypeOf(KClassifier classifier) {
|
||||
return factory.typeOf(classifier, Collections.<KTypeProjection>emptyList(), true);
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static KType nullableTypeOf(Class klass) {
|
||||
return factory.typeOf(getOrCreateKotlinClass(klass), Collections.<KTypeProjection>emptyList(), true);
|
||||
@@ -156,4 +166,21 @@ public class Reflection {
|
||||
public static KType nullableTypeOf(Class klass, KTypeProjection... arguments) {
|
||||
return factory.typeOf(getOrCreateKotlinClass(klass), ArraysKt.<KTypeProjection>toList(arguments), true);
|
||||
}
|
||||
|
||||
// Support of non-reified type parameters for typeOf
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static KTypeParameter typeParameter(Object container, String name, KVariance variance, boolean isReified) {
|
||||
return factory.typeParameter(container, name, variance, isReified);
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static void setUpperBounds(KTypeParameter typeParameter, KType bound) {
|
||||
factory.setUpperBounds(typeParameter, Collections.singletonList(bound));
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public static void setUpperBounds(KTypeParameter typeParameter, KType... bounds) {
|
||||
factory.setUpperBounds(typeParameter, ArraysKt.toList(bounds));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import kotlin.reflect.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public class ReflectionFactory {
|
||||
private static final String KOTLIN_JVM_FUNCTIONS = "kotlin.jvm.functions.";
|
||||
|
||||
@@ -82,4 +83,14 @@ public class ReflectionFactory {
|
||||
public KType typeOf(KClassifier klass, List<KTypeProjection> arguments, boolean isMarkedNullable) {
|
||||
return new TypeReference(klass, arguments, isMarkedNullable);
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public KTypeParameter typeParameter(Object container, String name, KVariance variance, boolean isReified) {
|
||||
return new TypeParameterReference(container, name, variance, isReified);
|
||||
}
|
||||
|
||||
@SinceKotlin(version = "1.4")
|
||||
public void setUpperBounds(KTypeParameter typeParameter, List<KType> bounds) {
|
||||
((TypeParameterReference) typeParameter).setUpperBounds(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package kotlin.jvm.internal
|
||||
|
||||
import kotlin.reflect.KType
|
||||
import kotlin.reflect.KTypeParameter
|
||||
import kotlin.reflect.KVariance
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
@SinceKotlin("1.4")
|
||||
class TypeParameterReference(
|
||||
private val container: Any?, // Either ClassReference or CallableReference
|
||||
override val name: String,
|
||||
override val variance: KVariance,
|
||||
override val isReified: Boolean,
|
||||
) : KTypeParameter {
|
||||
@Volatile
|
||||
private var bounds: List<KType>? = null
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
override val upperBounds: List<KType>
|
||||
get() = bounds ?: listOf(typeOf<Any?>()).also { bounds = it }
|
||||
|
||||
fun setUpperBounds(upperBounds: List<KType>) {
|
||||
// This assertion is only checking that the typeOf compiler implementation didn't generate some nonsense in bytecode.
|
||||
// Since this class is not used anywhere else, we don't use any locks to prevent double initialization here intentionally.
|
||||
if (bounds != null) {
|
||||
error("Upper bounds of type parameter '$this' have already been initialized.")
|
||||
}
|
||||
bounds = upperBounds
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is TypeParameterReference && container == other.container && name == other.name
|
||||
|
||||
override fun hashCode(): Int =
|
||||
container.hashCode() * 31 + name.hashCode()
|
||||
|
||||
override fun toString(): String = toString(this)
|
||||
|
||||
companion object {
|
||||
fun toString(typeParameter: KTypeParameter): String =
|
||||
buildString {
|
||||
when (typeParameter.variance) {
|
||||
KVariance.INVARIANT -> {
|
||||
}
|
||||
KVariance.IN -> append("in ")
|
||||
KVariance.OUT -> append("out ")
|
||||
}
|
||||
|
||||
append(typeParameter.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user