[JS] Support typeOf
This commit is contained in:
@@ -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"
|
||||
}
|
||||
+13
@@ -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)
|
||||
|
||||
+13
@@ -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)
|
||||
|
||||
+13
@@ -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 {
|
||||
|
||||
+15
-6
@@ -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)
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
Generated
+43
@@ -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)
|
||||
|
||||
+43
@@ -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";
|
||||
|
||||
+2
-1
@@ -39,7 +39,8 @@ class FunctionIntrinsics {
|
||||
AsDynamicFIF,
|
||||
CoroutineContextFIF,
|
||||
SuspendCoroutineUninterceptedOrReturnFIF,
|
||||
InterceptedFIF
|
||||
InterceptedFIF,
|
||||
TypeOfFIF
|
||||
)
|
||||
|
||||
fun getIntrinsic(descriptor: FunctionDescriptor, context: TranslationContext): FunctionIntrinsic? {
|
||||
|
||||
+111
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user