[JS] Support typeOf

This commit is contained in:
Svyatoslav Kuzmich
2019-09-11 19:22:54 +03:00
parent c1e1dbd83e
commit 7592048437
28 changed files with 670 additions and 12 deletions
@@ -126,6 +126,9 @@ val reducedRuntimeSources by task<Sync> {
"libraries/stdlib/js/src/kotlin/regexp.kt",
"libraries/stdlib/js/src/kotlin/sequence.kt",
"libraries/stdlib/js/src/kotlin/text/**",
"libraries/stdlib/js/src/kotlin/reflect/KTypeHelpers.kt",
"libraries/stdlib/js/src/kotlin/reflect/KTypeParameterImpl.kt",
"libraries/stdlib/js/src/kotlin/reflect/KTypeImpl.kt",
"libraries/stdlib/src/kotlin/collections/**",
"libraries/stdlib/src/kotlin/experimental/bitwiseOperations.kt",
"libraries/stdlib/src/kotlin/properties/Delegates.kt",
@@ -0,0 +1,42 @@
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JS
// IGNORE_BACKEND: JS_IR
// 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("Any", typeOf<Any>())
check("String", typeOf<String>())
check("String?", typeOf<String?>())
check("Unit", typeOf<Unit>())
check("C", typeOf<C>())
check("C?", typeOf<C?>())
check("List<String>", typeOf<List<String>>())
check("Map<in Number, *>?", typeOf<Map<in Number, *>?>())
check("Enum<*>", typeOf<Enum<*>>())
check("Enum<AnnotationRetention>", typeOf<Enum<AnnotationRetention>>())
check("Array<Any>", typeOf<Array<Any>>())
check("Array<*>", typeOf<Array<*>>())
check("Array<IntArray>", typeOf<Array<IntArray>>())
check("Array<in Array<C>?>", typeOf<Array<in Array<C>?>>())
check("Int", typeOf<Int>())
check("Int?", typeOf<Int?>())
check("Boolean", typeOf<Boolean>())
return "OK"
}
@@ -0,0 +1,33 @@
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JS
// IGNORE_BACKEND: JS_IR
// 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("Z", typeOf<Z>())
check("Z?", typeOf<Z?>())
check("Array<Z>", typeOf<Array<Z>>())
check("Array<Z?>", typeOf<Array<Z?>>())
check("UInt", typeOf<UInt>())
check("UInt?", typeOf<UInt?>())
check("ULong?", typeOf<ULong?>())
check("UShortArray", typeOf<UShortArray>())
check("UShortArray?", typeOf<UShortArray?>())
check("Array<UByteArray>", typeOf<Array<UByteArray>>())
check("Array<UByteArray?>?", typeOf<Array<UByteArray?>?>())
return "OK"
}
@@ -0,0 +1,57 @@
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JS
// IGNORE_BACKEND: JS_IR
// WITH_REFLECT
import kotlin.test.*
import kotlin.reflect.*
inline fun <reified R> kType() = typeOf<R>()
inline fun <reified R> kType(obj: R) = kType<R>()
class C<T>
class D
fun <T> kTypeForCWithTypeParameter() = kType<C<T>>()
class Outer<T> {
companion object Friend
inner class Inner<S>
}
object Object
fun testBasics1() {
assertEquals("C<Int?>", kType<C<Int?>>().toString())
assertEquals("C<C<Any>>", kType<C<C<Any>>>().toString())
assertEquals("C<T>", kTypeForCWithTypeParameter<D>().toString())
assertEquals("Object", kType<Object>().toString())
assertEquals("Friend", kType<Outer.Friend>().toString())
}
fun testInner() {
val innerKType = kType<Outer<D>.Inner<String>>()
assertEquals(Outer.Inner::class, innerKType.classifier)
assertEquals(String::class, innerKType.arguments.first().type!!.classifier)
assertEquals(D::class, innerKType.arguments.last().type!!.classifier)
}
fun testAnonymousObject() {
val obj = object {}
val objType = kType(obj)
assertEquals("(non-denotable type)", objType.toString())
assertEquals(obj::class, objType.classifier)
assertTrue(objType.arguments.isEmpty())
assertFalse(objType.isMarkedNullable)
}
fun box(): String {
testBasics1()
testInner()
testAnonymousObject()
return "OK"
}
@@ -0,0 +1,32 @@
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JS
// IGNORE_BACKEND: JS_IR
// 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(
"C<I1, I2, I3?, in I4, out I5, I6, I7?>",
typeOf<C<I1, I2, I3?, in I4, out I5, I6, I7?>>().toString()
)
assertEquals(
"C<out I1, I2?, I3, I4, I5, I6?, in I7>?",
typeOf<C<out I1, I2?, I3, I4, I5, I6?, in I7>?>().toString()
)
return "OK"
}
@@ -0,0 +1,27 @@
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JS
// IGNORE_BACKEND: JS_IR
// WITH_REFLECT
package test
import kotlin.reflect.typeOf
import kotlin.reflect.KType
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(): KType {
return get1<Map<in V?, Array<V>>>()
}
fun box(): String {
assertEquals("C?", get1<C>().toString())
assertEquals("Map<in C?, Array<C>>?", get2<C>().toString())
assertEquals("Map<in List<C>?, Array<List<C>>>?", get2<List<C>>().toString())
return "OK"
}
@@ -0,0 +1,40 @@
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JS
// IGNORE_BACKEND: JS_IR
// WITH_REFLECT
// MODULE: lib1
// FILE: lib1.kt
import kotlin.reflect.typeOf
inline fun <reified T> get() = typeOf<T>()
// MODULE: lib2(lib1)
// FILE: lib2.kt
inline fun <reified U> get1() = get<U?>()
// MODULE: lib3(lib1, lib2)
// FILE: lib3.kt
import kotlin.reflect.KType
inline fun <reified V> get2(): KType {
return get1<Map<in V?, Array<V>>>()
}
// MODULE: main(lib1, lib2, lib3)
// FILE: lib4.kt
import kotlin.test.assertEquals
interface C
fun box(): String {
assertEquals("C?", get1<C>().toString())
assertEquals("Map<in C?, Array<C>>?", get2<C>().toString())
assertEquals("Map<in List<C>?, Array<List<C>>>?", get2<List<C>>().toString())
assertEquals("Short?", get1<Short>().toString())
assertEquals("Map<in Short?, Array<Short>>?", get2<Short>().toString())
assertEquals("Map<in List<Short>?, Array<List<Short>>>?", get2<List<Short>>().toString())
return "OK"
}
@@ -22565,6 +22565,19 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
}
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/js")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Js extends AbstractBlackBoxCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInJs() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf/js"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
}
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/noReflect")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -22565,6 +22565,19 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
}
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/js")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Js extends AbstractLightAnalysisModeTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInJs() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf/js"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
}
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/noReflect")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -21455,6 +21455,19 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
}
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/js")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Js extends AbstractIrBlackBoxCodegenTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
}
public void testAllFilesPresentInJs() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf/js"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
}
}
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/noReflect")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -129,6 +129,8 @@ var JsExpression.range: Pair<RangeType, RangeKind>? by MetadataProperty(default
var JsExpression.primitiveKClass: JsExpression? by MetadataProperty(default = null)
var JsExpression.kType: JsExpression? by MetadataProperty(default = null)
data class CoroutineMetadata(
val doResumeName: JsName,
val stateName: JsName,
@@ -166,7 +168,8 @@ enum class SpecialFunction(val suggestedName: String) {
COROUTINE_CONTROLLER("coroutineController"),
COROUTINE_RECEIVER("coroutineReceiver"),
SET_COROUTINE_RESULT("setCoroutineResult"),
GET_KCLASS("getKClass")
GET_KCLASS("getKClass"),
GET_REIFIED_TYPE_PARAMETER_KTYPE("getReifiedTypeParameterKType")
}
enum class BoxingKind {
@@ -23,19 +23,27 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.NotFoundClasses
import org.jetbrains.kotlin.diagnostics.Errors.UNSUPPORTED
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.checkers.AbstractReflectionApiCallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.storage.getValue
private val ALLOWED_KCLASS_MEMBERS = setOf("simpleName", "isInstance")
private val ALLOWED_CLASSES = setOf(
FqName("kotlin.reflect.KType"),
FqName("kotlin.reflect.KTypeProjection"),
FqName("kotlin.reflect.KTypeProjection.Companion"),
FqName("kotlin.reflect.KVariance")
)
class JsReflectionAPICallChecker(
module: ModuleDescriptor,
private val reflectionTypes: ReflectionTypes,
notFoundClasses: NotFoundClasses,
storageManager: StorageManager
module: ModuleDescriptor,
private val reflectionTypes: ReflectionTypes,
notFoundClasses: NotFoundClasses,
storageManager: StorageManager
) : AbstractReflectionApiCallChecker(module, notFoundClasses, storageManager) {
override val isWholeReflectionApiAvailable: Boolean
get() = false
@@ -47,6 +55,7 @@ class JsReflectionAPICallChecker(
private val kClass by storageManager.createLazyValue { reflectionTypes.kClass }
override fun isAllowedReflectionApi(descriptor: CallableDescriptor, containingClass: ClassDescriptor): Boolean =
super.isAllowedReflectionApi(descriptor, containingClass) ||
DescriptorUtils.isSubclass(containingClass, kClass) && descriptor.name.asString() in ALLOWED_KCLASS_MEMBERS
super.isAllowedReflectionApi(descriptor, containingClass) ||
DescriptorUtils.isSubclass(containingClass, kClass) && descriptor.name.asString() in ALLOWED_KCLASS_MEMBERS ||
containingClass.fqNameSafe in ALLOWED_CLASSES
}
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.js.backend.ast.metadata.inlineStrategy
import org.jetbrains.kotlin.js.backend.ast.metadata.psiElement
import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor
import org.jetbrains.kotlin.js.inline.clean.removeUnusedLocalFunctionDeclarations
import org.jetbrains.kotlin.js.inline.clean.substituteKTypes
import org.jetbrains.kotlin.js.inline.util.extractFunction
import org.jetbrains.kotlin.js.inline.util.refreshLabelNames
import org.jetbrains.kotlin.js.translate.expression.InlineMetadata
@@ -47,11 +48,11 @@ class InlineAstVisitor(
}
override fun endVisit(function: JsFunction, ctx: JsContext<*>) {
// Cleanup
patchReturnsFromSecondaryConstructor(function)
refreshLabelNames(function.body, function.scope)
removeUnusedLocalFunctionDeclarations(function)
FunctionPostProcessor(function).apply()
substituteKTypes(function)
}
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2019 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 org.jetbrains.kotlin.js.inline.clean
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction
import org.jetbrains.kotlin.js.backend.ast.metadata.kType
import org.jetbrains.kotlin.js.backend.ast.metadata.specialFunction
// Replaces getReifiedTypeParameterKType(<Class Constructor>) with its KType
fun substituteKTypes(root: JsNode) {
val visitor = object : JsVisitorWithContextImpl() {
override fun endVisit(invocation: JsInvocation, ctx: JsContext<in JsNode>) {
val qualifier = invocation.qualifier as? JsNameRef ?: return
if (qualifier.name?.specialFunction != SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE) return
val firstArg = invocation.arguments.first()
firstArg.kType?.let {
ctx.replaceMe(it)
}
}
}
visitor.accept(root)
}
+1
View File
@@ -465,6 +465,7 @@ enum SpecialFunction {
COROUTINE_RECEIVER = 8;
SET_COROUTINE_RESULT = 9;
GET_KCLASS = 10;
GET_REIFIED_TYPE_PARAMETER_KTYPE = 11;
}
@@ -558,6 +558,7 @@ class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable<Fi
JsAstProtoBuf.SpecialFunction.COROUTINE_RECEIVER -> SpecialFunction.COROUTINE_RECEIVER
JsAstProtoBuf.SpecialFunction.SET_COROUTINE_RESULT -> SpecialFunction.SET_COROUTINE_RESULT
JsAstProtoBuf.SpecialFunction.GET_KCLASS -> SpecialFunction.GET_KCLASS
JsAstProtoBuf.SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE -> SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE
}
private fun <T : JsNode> withLocation(fileId: Int?, location: Location?, action: () -> T): T {
@@ -183,6 +183,10 @@ public final class JsAstProtoBuf {
* <code>GET_KCLASS = 10;</code>
*/
GET_KCLASS(9, 10),
/**
* <code>GET_REIFIED_TYPE_PARAMETER_KTYPE = 11;</code>
*/
GET_REIFIED_TYPE_PARAMETER_KTYPE(10, 11),
;
/**
@@ -225,6 +229,10 @@ public final class JsAstProtoBuf {
* <code>GET_KCLASS = 10;</code>
*/
public static final int GET_KCLASS_VALUE = 10;
/**
* <code>GET_REIFIED_TYPE_PARAMETER_KTYPE = 11;</code>
*/
public static final int GET_REIFIED_TYPE_PARAMETER_KTYPE_VALUE = 11;
public final int getNumber() { return value; }
@@ -241,6 +249,7 @@ public final class JsAstProtoBuf {
case 8: return COROUTINE_RECEIVER;
case 9: return SET_COROUTINE_RESULT;
case 10: return GET_KCLASS;
case 11: return GET_REIFIED_TYPE_PARAMETER_KTYPE;
default: return null;
}
}
@@ -601,6 +601,7 @@ class JsAstSerializer(private val jsAstValidator: ((JsProgramFragment, Set<JsNam
SpecialFunction.COROUTINE_RECEIVER -> JsAstProtoBuf.SpecialFunction.COROUTINE_RECEIVER
SpecialFunction.SET_COROUTINE_RESULT -> JsAstProtoBuf.SpecialFunction.SET_COROUTINE_RESULT
SpecialFunction.GET_KCLASS -> JsAstProtoBuf.SpecialFunction.GET_KCLASS
SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE -> JsAstProtoBuf.SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE
}
private fun serialize(name: JsName): Int = nameMap.getOrPut(name) {
@@ -17310,6 +17310,49 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
}
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/js")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Js extends AbstractIrJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS_IR, testDataFilePath);
}
public void testAllFilesPresentInJs() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf/js"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS_IR, true);
}
@TestMetadata("classes.kt")
public void testClasses() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/js/classes.kt");
}
@TestMetadata("inlineClasses.kt")
public void testInlineClasses() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/js/inlineClasses.kt");
}
@TestMetadata("kType.kt")
public void testKType() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/js/kType.kt");
}
@TestMetadata("manyTypeArguments.kt")
public void testManyTypeArguments() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/js/manyTypeArguments.kt");
}
@TestMetadata("multipleLayers.kt")
public void testMultipleLayers() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/js/multipleLayers.kt");
}
@TestMetadata("multipleModules.kt")
public void testMultipleModules() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/js/multipleModules.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/noReflect")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -18465,6 +18465,49 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/reflection/typeOf/multipleLayers.kt");
}
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/js")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Js extends AbstractJsCodegenBoxTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest0(this::doTest, TargetBackend.JS, testDataFilePath);
}
public void testAllFilesPresentInJs() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/typeOf/js"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("classes.kt")
public void testClasses() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/js/classes.kt");
}
@TestMetadata("inlineClasses.kt")
public void testInlineClasses() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/js/inlineClasses.kt");
}
@TestMetadata("kType.kt")
public void testKType() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/js/kType.kt");
}
@TestMetadata("manyTypeArguments.kt")
public void testManyTypeArguments() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/js/manyTypeArguments.kt");
}
@TestMetadata("multipleLayers.kt")
public void testMultipleLayers() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/js/multipleLayers.kt");
}
@TestMetadata("multipleModules.kt")
public void testMultipleModules() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/js/multipleModules.kt");
}
}
@TestMetadata("compiler/testData/codegen/box/reflection/typeOf/noReflect")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -75,6 +75,15 @@ public final class Namer {
public static final String GET_KCLASS = "getKClass";
public static final String GET_KCLASS_FROM_EXPRESSION = "getKClassFromExpression";
public static final String CREATE_KTYPE = "createKType";
public static final String MARK_KTYPE_NULLABLE = "markKTypeNullable";
public static final String CREATE_KTYPE_PARAMETER = "createKTypeParameter";
public static final String CREATE_REIFIED_KTYPE_PARAMETER = "getReifiedTypeParameterKType";
public static final String GET_START_KTYPE_PROJECTION = "getStarKTypeProjection";
public static final String CREATE_COVARIANT_KTYPE_PROJECTION = "createCovariantKTypeProjection";
public static final String CREATE_INVARIANT_KTYPE_PROJECTION = "createInvariantKTypeProjection";
public static final String CREATE_CONTRAVARIANT_KTYPE_PROJECTION = "createContravariantKTypeProjection";
public static final String CALLEE_NAME = "$fun";
public static final String CALL_FUNCTION = "call";
@@ -39,7 +39,8 @@ class FunctionIntrinsics {
AsDynamicFIF,
CoroutineContextFIF,
SuspendCoroutineUninterceptedOrReturnFIF,
InterceptedFIF
InterceptedFIF,
TypeOfFIF
)
fun getIntrinsic(descriptor: FunctionDescriptor, context: TranslationContext): FunctionIntrinsic? {
@@ -0,0 +1,111 @@
/*
* Copyright 2010-2019 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 org.jetbrains.kotlin.js.translate.intrinsic.functions.factories
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction
import org.jetbrains.kotlin.js.backend.ast.metadata.specialFunction
import org.jetbrains.kotlin.js.translate.callTranslator.CallInfo
import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.expression.ExpressionVisitor
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic
import org.jetbrains.kotlin.js.translate.utils.getReferenceToJsClass
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.TypeProjection
import org.jetbrains.kotlin.types.Variance
object TypeOfFIF : FunctionIntrinsicFactory {
override fun getIntrinsic(descriptor: FunctionDescriptor, context: TranslationContext): FunctionIntrinsic? =
Intrinsic.takeIf { descriptor.fqNameUnsafe.asString() == "kotlin.reflect.typeOf" }
object Intrinsic : FunctionIntrinsic() {
override fun apply(callInfo: CallInfo, arguments: List<JsExpression>, context: TranslationContext): JsExpression {
val type = callInfo.resolvedCall.typeArguments.values.single() as SimpleType
return KTypeConstructor(context).createKType(type)
}
}
}
class KTypeConstructor(val context: TranslationContext) {
fun callHelperFunction(name: String, vararg arguments: JsExpression) =
JsInvocation(context.getReferenceToIntrinsic(name), *arguments)
fun createKType(type: SimpleType): JsExpression {
val classifier: ClassifierDescriptor = type.constructor.declarationDescriptor!!
if (classifier is TypeParameterDescriptor && classifier.isReified) {
val kClassName = context.getNameForIntrinsic(SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE.suggestedName)
kClassName.specialFunction = SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE
val reifiedTypeParameterType = JsInvocation(kClassName.makeRef(), getReferenceToJsClass(classifier, context))
if (type.isMarkedNullable) {
return callHelperFunction(Namer.MARK_KTYPE_NULLABLE, reifiedTypeParameterType)
}
return reifiedTypeParameterType
}
val kClassifier = createKClassifier(classifier)
val arguments = JsArrayLiteral(type.arguments.map { createKTypeProjection(it) })
val isMarkedNullable = JsBooleanLiteral(type.isMarkedNullable)
return callHelperFunction(
Namer.CREATE_KTYPE,
kClassifier,
arguments,
isMarkedNullable
)
}
fun createKTypeProjection(tp: TypeProjection): JsExpression {
if (tp.isStarProjection) {
return callHelperFunction(Namer.GET_START_KTYPE_PROJECTION)
}
val factoryName = when (tp.projectionKind) {
Variance.INVARIANT -> Namer.CREATE_INVARIANT_KTYPE_PROJECTION
Variance.IN_VARIANCE -> Namer.CREATE_CONTRAVARIANT_KTYPE_PROJECTION
Variance.OUT_VARIANCE -> Namer.CREATE_COVARIANT_KTYPE_PROJECTION
}
val kType = createKType(tp.type as SimpleType)
return callHelperFunction(factoryName, kType)
}
fun createKClassifier(classifier: ClassifierDescriptor): JsExpression =
when (classifier) {
is TypeParameterDescriptor -> createKTypeParameter(classifier)
else -> ExpressionVisitor.getObjectKClass(context, classifier)
}
fun createKTypeParameter(typeParameter: TypeParameterDescriptor): JsExpression {
val name = JsStringLiteral(typeParameter.name.asString())
val upperBounds = JsArrayLiteral(typeParameter.upperBounds.map { createKType(it as SimpleType) })
val variance = when (typeParameter.variance) {
Variance.INVARIANT -> JsStringLiteral("invariant")
Variance.IN_VARIANCE -> JsStringLiteral("in")
Variance.OUT_VARIANCE -> JsStringLiteral("out")
}
if (typeParameter.isReified) {
val kClassName = context.getNameForIntrinsic(SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE.suggestedName)
kClassName.specialFunction = SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE
return JsInvocation(kClassName.makeRef(), getReferenceToJsClass(typeParameter, context))
}
return callHelperFunction(
Namer.CREATE_KTYPE_PARAMETER,
name,
upperBounds,
variance
)
}
}
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.js.translate.context.Namer
import org.jetbrains.kotlin.js.translate.context.TranslationContext
import org.jetbrains.kotlin.js.translate.expression.ExpressionVisitor
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsicWithReceiverComputed
import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.KTypeConstructor
import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunction
import org.jetbrains.kotlin.psi.*
@@ -39,6 +40,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.Receiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.utils.DFS
@@ -126,7 +128,9 @@ fun <T, S> List<T>.splitToRanges(classifier: (T) -> S): List<Pair<List<T>, S>> {
}
fun getReferenceToJsClass(type: KotlinType, context: TranslationContext): JsExpression =
getReferenceToJsClass(type.constructor.declarationDescriptor, context)
getReferenceToJsClass(type.constructor.declarationDescriptor, context).also {
it.kType = KTypeConstructor(context).createKType(type as SimpleType)
}
fun getReferenceToJsClass(classifierDescriptor: ClassifierDescriptor?, context: TranslationContext): JsExpression {
return when (classifierDescriptor) {
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2018 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.
*/
// a package is omitted to get declarations directly under the module
// TODO: Remove once JsReflectionAPICallChecker supports more reflection types
@file:Suppress("Unsupported")
import kotlin.reflect.*
import kotlin.reflect.js.internal.*
@JsName("createKType")
internal fun createKType(
classifier: KClassifier,
arguments: Array<KTypeProjection>,
isMarkedNullable: Boolean
) =
KTypeImpl(classifier, arguments.asList(), isMarkedNullable)
@JsName("markKTypeNullable")
internal fun markKTypeNullable(kType: KType) = KTypeImpl(kType.classifier!!, kType.arguments, true)
@JsName("createKTypeParameter")
internal fun createKTypeParameter(
name: String,
upperBounds: Array<KType>,
variance: String
): KTypeParameter {
val kVariance = when (variance) {
"in" -> KVariance.IN
"out" -> KVariance.OUT
else -> KVariance.INVARIANT
}
return KTypeParameterImpl(name, upperBounds.asList(), kVariance, false)
}
@JsName("getStarKTypeProjection")
internal fun getStarKTypeProjection(): KTypeProjection =
KTypeProjection.STAR
@JsName("createCovariantKTypeProjection")
internal fun createCovariantKTypeProjection(type: KType): KTypeProjection =
KTypeProjection.covariant(type)
@JsName("createInvariantKTypeProjection")
internal fun createInvariantKTypeProjection(type: KType): KTypeProjection =
KTypeProjection.invariant(type)
@JsName("createContravariantKTypeProjection")
internal fun createContravariantKTypeProjection(type: KType): KTypeProjection =
KTypeProjection.contravariant(type)
@@ -0,0 +1,53 @@
/*
* Copyright 2010-2019 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.reflect.js.internal
import kotlin.reflect.*
internal class KTypeImpl(
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 KTypeImpl &&
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 {
val kClass = (classifier as? KClass<*>)
val classifierName = when {
kClass == null -> classifier.toString()
kClass.simpleName != null -> kClass.simpleName
else -> "(non-denotable type)"
}
val args =
if (arguments.isEmpty()) ""
else arguments.joinToString(", ", "<", ">") { it.asString() }
val nullable = if (isMarkedNullable) "?" else ""
return classifierName + args + nullable
}
// TODO: this should be the implementation of KTypeProjection.toString, see KT-30071
private fun KTypeProjection.asString(): String {
if (variance == null) return "*"
return variance.prefixString() + type.toString()
}
}
internal fun KVariance.prefixString() =
when (this) {
KVariance.INVARIANT -> ""
KVariance.IN -> "in "
KVariance.OUT -> "out "
}
@@ -0,0 +1,17 @@
/*
* Copyright 2010-2019 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.reflect.js.internal
import kotlin.reflect.*
internal data class KTypeParameterImpl(
override val name: String,
override val upperBounds: List<KType>,
override val variance: KVariance,
override val isReified: Boolean
) : KTypeParameter {
override fun toString(): String = name
}
@@ -5,7 +5,7 @@
// a package is omitted to get declarations directly under the module
import kotlin.reflect.KClass
import kotlin.reflect.*
import kotlin.reflect.js.internal.*
@JsName("getKClass")
@@ -62,4 +62,3 @@ private fun <T : Any> getOrCreateKClass(jClass: JsClass<T>): KClass<T> {
SimpleKClassImpl(jClass)
}
}