Support non-reified type parameters in typeOf in JVM and JVM_IR

#KT-30279 Fixed
This commit is contained in:
Alexander Udalov
2020-01-31 14:13:11 +01:00
committed by Alexander Udalov
parent 6fb40878c4
commit 0ce16b9d8c
46 changed files with 1748 additions and 122 deletions
@@ -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)
}
}
}