From 75920484371ac55478a9a5969d4cf613101f46d0 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kuzmich Date: Wed, 11 Sep 2019 19:22:54 +0300 Subject: [PATCH] [JS] Support typeOf --- compiler/ir/serialization.js/build.gradle.kts | 3 + .../box/reflection/typeOf/js/classes.kt | 42 +++++++ .../box/reflection/typeOf/js/inlineClasses.kt | 33 ++++++ .../codegen/box/reflection/typeOf/js/kType.kt | 57 +++++++++ .../reflection/typeOf/js/manyTypeArguments.kt | 32 +++++ .../reflection/typeOf/js/multipleLayers.kt | 27 +++++ .../reflection/typeOf/js/multipleModules.kt | 40 +++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 13 ++ .../LightAnalysisModeTestGenerated.java | 13 ++ .../ir/IrBlackBoxCodegenTestGenerated.java | 13 ++ .../ast/metadata/metadataProperties.kt | 5 +- .../diagnostics/JsReflectionAPICallChecker.kt | 21 +++- .../kotlin/js/inline/InlineAstVisitor.kt | 3 +- .../js/inline/clean/substituteKTypes.kt | 26 ++++ js/js.serializer/src/js-ast.proto | 1 + .../serialization/js/ast/JsAstDeserializer.kt | 1 + .../serialization/js/ast/JsAstProtoBuf.java | 9 ++ .../serialization/js/ast/JsAstSerializer.kt | 1 + .../IrJsCodegenBoxTestGenerated.java | 43 +++++++ .../semantics/JsCodegenBoxTestGenerated.java | 43 +++++++ .../kotlin/js/translate/context/Namer.java | 9 ++ .../intrinsic/functions/FunctionIntrinsics.kt | 3 +- .../functions/factories/TypeOfFIF.kt | 111 ++++++++++++++++++ .../kotlin/js/translate/utils/utils.kt | 6 +- .../js/src/kotlin/reflect/KTypeHelpers.kt | 54 +++++++++ .../stdlib/js/src/kotlin/reflect/KTypeImpl.kt | 53 +++++++++ .../src/kotlin/reflect/KTypeParameterImpl.kt | 17 +++ .../js/src/kotlin/reflect/reflection.kt | 3 +- 28 files changed, 670 insertions(+), 12 deletions(-) create mode 100644 compiler/testData/codegen/box/reflection/typeOf/js/classes.kt create mode 100644 compiler/testData/codegen/box/reflection/typeOf/js/inlineClasses.kt create mode 100644 compiler/testData/codegen/box/reflection/typeOf/js/kType.kt create mode 100644 compiler/testData/codegen/box/reflection/typeOf/js/manyTypeArguments.kt create mode 100644 compiler/testData/codegen/box/reflection/typeOf/js/multipleLayers.kt create mode 100644 compiler/testData/codegen/box/reflection/typeOf/js/multipleModules.kt create mode 100644 js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/substituteKTypes.kt create mode 100644 js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TypeOfFIF.kt create mode 100644 libraries/stdlib/js/src/kotlin/reflect/KTypeHelpers.kt create mode 100644 libraries/stdlib/js/src/kotlin/reflect/KTypeImpl.kt create mode 100644 libraries/stdlib/js/src/kotlin/reflect/KTypeParameterImpl.kt diff --git a/compiler/ir/serialization.js/build.gradle.kts b/compiler/ir/serialization.js/build.gradle.kts index 6d98c2fa405..ac6affed0c1 100644 --- a/compiler/ir/serialization.js/build.gradle.kts +++ b/compiler/ir/serialization.js/build.gradle.kts @@ -126,6 +126,9 @@ val reducedRuntimeSources by task { "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", diff --git a/compiler/testData/codegen/box/reflection/typeOf/js/classes.kt b/compiler/testData/codegen/box/reflection/typeOf/js/classes.kt new file mode 100644 index 00000000000..8b16dbf89f3 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/js/classes.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()) + check("String", typeOf()) + check("String?", typeOf()) + check("Unit", typeOf()) + + check("C", typeOf()) + check("C?", typeOf()) + + check("List", typeOf>()) + check("Map?", typeOf?>()) + check("Enum<*>", typeOf>()) + check("Enum", typeOf>()) + + check("Array", typeOf>()) + check("Array<*>", typeOf>()) + check("Array", typeOf>()) + check("Array?>", typeOf?>>()) + + check("Int", typeOf()) + check("Int?", typeOf()) + check("Boolean", typeOf()) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/typeOf/js/inlineClasses.kt b/compiler/testData/codegen/box/reflection/typeOf/js/inlineClasses.kt new file mode 100644 index 00000000000..77506627e2a --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/js/inlineClasses.kt @@ -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()) + check("Z?", typeOf()) + check("Array", typeOf>()) + check("Array", typeOf>()) + + check("UInt", typeOf()) + check("UInt?", typeOf()) + check("ULong?", typeOf()) + check("UShortArray", typeOf()) + check("UShortArray?", typeOf()) + check("Array", typeOf>()) + check("Array?", typeOf?>()) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/typeOf/js/kType.kt b/compiler/testData/codegen/box/reflection/typeOf/js/kType.kt new file mode 100644 index 00000000000..e03a1f492da --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/js/kType.kt @@ -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 kType() = typeOf() + +inline fun kType(obj: R) = kType() + +class C +class D + +fun kTypeForCWithTypeParameter() = kType>() + +class Outer { + companion object Friend + inner class Inner +} + +object Object + +fun testBasics1() { + assertEquals("C", kType>().toString()) + assertEquals("C>", kType>>().toString()) + + assertEquals("C", kTypeForCWithTypeParameter().toString()) + assertEquals("Object", kType().toString()) + assertEquals("Friend", kType().toString()) +} + +fun testInner() { + val innerKType = kType.Inner>() + 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" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/reflection/typeOf/js/manyTypeArguments.kt b/compiler/testData/codegen/box/reflection/typeOf/js/manyTypeArguments.kt new file mode 100644 index 00000000000..a0990b30cab --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/js/manyTypeArguments.kt @@ -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 + +fun box(): String { + assertEquals( + "C", + typeOf>().toString() + ) + assertEquals( + "C?", + typeOf?>().toString() + ) + + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/typeOf/js/multipleLayers.kt b/compiler/testData/codegen/box/reflection/typeOf/js/multipleLayers.kt new file mode 100644 index 00000000000..c0d1fe42f15 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/js/multipleLayers.kt @@ -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 get() = typeOf() + +inline fun get1() = get() + +inline fun get2(): KType { + return get1>>() +} + +fun box(): String { + assertEquals("C?", get1().toString()) + assertEquals("Map>?", get2().toString()) + assertEquals("Map?, Array>>?", get2>().toString()) + return "OK" +} diff --git a/compiler/testData/codegen/box/reflection/typeOf/js/multipleModules.kt b/compiler/testData/codegen/box/reflection/typeOf/js/multipleModules.kt new file mode 100644 index 00000000000..c9a54b40d09 --- /dev/null +++ b/compiler/testData/codegen/box/reflection/typeOf/js/multipleModules.kt @@ -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 get() = typeOf() + +// MODULE: lib2(lib1) +// FILE: lib2.kt +inline fun get1() = get() + +// MODULE: lib3(lib1, lib2) +// FILE: lib3.kt +import kotlin.reflect.KType + +inline fun get2(): KType { + return get1>>() +} + +// MODULE: main(lib1, lib2, lib3) +// FILE: lib4.kt +import kotlin.test.assertEquals + +interface C + +fun box(): String { + assertEquals("C?", get1().toString()) + assertEquals("Map>?", get2().toString()) + assertEquals("Map?, Array>>?", get2>().toString()) + + assertEquals("Short?", get1().toString()) + assertEquals("Map>?", get2().toString()) + assertEquals("Map?, Array>>?", get2>().toString()) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 4a3be830b81..07ca4190041 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -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) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 32e38204923..420563b0a48 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -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) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 446ff1a0de3..691ad26b42c 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -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) diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt index 2a88307fa3d..5d170f4f146 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/metadata/metadataProperties.kt @@ -129,6 +129,8 @@ var JsExpression.range: Pair? 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 { diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt index 4e770395036..0b84ff4e31c 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/resolve/diagnostics/JsReflectionAPICallChecker.kt @@ -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 } diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/InlineAstVisitor.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/InlineAstVisitor.kt index 248b5a05164..d19efc3dd20 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/InlineAstVisitor.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/InlineAstVisitor.kt @@ -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) } diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/substituteKTypes.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/substituteKTypes.kt new file mode 100644 index 00000000000..8076623c4ed --- /dev/null +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/clean/substituteKTypes.kt @@ -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() with its KType +fun substituteKTypes(root: JsNode) { + val visitor = object : JsVisitorWithContextImpl() { + override fun endVisit(invocation: JsInvocation, ctx: JsContext) { + 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) +} \ No newline at end of file diff --git a/js/js.serializer/src/js-ast.proto b/js/js.serializer/src/js-ast.proto index 974e5bd8104..febbd00909b 100644 --- a/js/js.serializer/src/js-ast.proto +++ b/js/js.serializer/src/js-ast.proto @@ -465,6 +465,7 @@ enum SpecialFunction { COROUTINE_RECEIVER = 8; SET_COROUTINE_RESULT = 9; GET_KCLASS = 10; + GET_REIFIED_TYPE_PARAMETER_KTYPE = 11; } diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstDeserializer.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstDeserializer.kt index 1d2497f5c0a..e87564dfdf2 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstDeserializer.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstDeserializer.kt @@ -558,6 +558,7 @@ class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable 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 withLocation(fileId: Int?, location: Location?, action: () -> T): T { diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java index ec4739ee311..1967910a8cd 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstProtoBuf.java @@ -183,6 +183,10 @@ public final class JsAstProtoBuf { * GET_KCLASS = 10; */ GET_KCLASS(9, 10), + /** + * GET_REIFIED_TYPE_PARAMETER_KTYPE = 11; + */ + GET_REIFIED_TYPE_PARAMETER_KTYPE(10, 11), ; /** @@ -225,6 +229,10 @@ public final class JsAstProtoBuf { * GET_KCLASS = 10; */ public static final int GET_KCLASS_VALUE = 10; + /** + * GET_REIFIED_TYPE_PARAMETER_KTYPE = 11; + */ + 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; } } diff --git a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstSerializer.kt b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstSerializer.kt index 1d8f1678db7..a6535fabdfc 100644 --- a/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstSerializer.kt +++ b/js/js.serializer/src/org/jetbrains/kotlin/serialization/js/ast/JsAstSerializer.kt @@ -601,6 +601,7 @@ class JsAstSerializer(private val jsAstValidator: ((JsProgramFragment, Set 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) { diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 1d28ef132bb..712db018ff9 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -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) diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 5f7e0f133b2..19c461e4303 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -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) diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java index 55eb10b48cb..4f550b9c76d 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/Namer.java @@ -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"; diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/FunctionIntrinsics.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/FunctionIntrinsics.kt index f80bf5033a4..ec2bc3a01ff 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/FunctionIntrinsics.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/FunctionIntrinsics.kt @@ -39,7 +39,8 @@ class FunctionIntrinsics { AsDynamicFIF, CoroutineContextFIF, SuspendCoroutineUninterceptedOrReturnFIF, - InterceptedFIF + InterceptedFIF, + TypeOfFIF ) fun getIntrinsic(descriptor: FunctionDescriptor, context: TranslationContext): FunctionIntrinsic? { diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TypeOfFIF.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TypeOfFIF.kt new file mode 100644 index 00000000000..1671b54023c --- /dev/null +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/intrinsic/functions/factories/TypeOfFIF.kt @@ -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, 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 + ) + } +} diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt index c065ad3da71..e4ccbd20e5e 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/utils.kt @@ -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 List.splitToRanges(classifier: (T) -> S): List, 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) { diff --git a/libraries/stdlib/js/src/kotlin/reflect/KTypeHelpers.kt b/libraries/stdlib/js/src/kotlin/reflect/KTypeHelpers.kt new file mode 100644 index 00000000000..9c3fd06a1da --- /dev/null +++ b/libraries/stdlib/js/src/kotlin/reflect/KTypeHelpers.kt @@ -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, + 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, + 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) diff --git a/libraries/stdlib/js/src/kotlin/reflect/KTypeImpl.kt b/libraries/stdlib/js/src/kotlin/reflect/KTypeImpl.kt new file mode 100644 index 00000000000..2c3e03c8d9c --- /dev/null +++ b/libraries/stdlib/js/src/kotlin/reflect/KTypeImpl.kt @@ -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, + override val isMarkedNullable: Boolean +) : KType { + override val annotations: List + 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 " + } diff --git a/libraries/stdlib/js/src/kotlin/reflect/KTypeParameterImpl.kt b/libraries/stdlib/js/src/kotlin/reflect/KTypeParameterImpl.kt new file mode 100644 index 00000000000..6b5fce7dde4 --- /dev/null +++ b/libraries/stdlib/js/src/kotlin/reflect/KTypeParameterImpl.kt @@ -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, + override val variance: KVariance, + override val isReified: Boolean +) : KTypeParameter { + override fun toString(): String = name +} \ No newline at end of file diff --git a/libraries/stdlib/js/src/kotlin/reflect/reflection.kt b/libraries/stdlib/js/src/kotlin/reflect/reflection.kt index df5d548d4a2..cdddf7c173f 100644 --- a/libraries/stdlib/js/src/kotlin/reflect/reflection.kt +++ b/libraries/stdlib/js/src/kotlin/reflect/reflection.kt @@ -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 getOrCreateKClass(jClass: JsClass): KClass { SimpleKClassImpl(jClass) } } -