From 8c7562d338cd6f87c46a2bcb2bb3c6b5ce6e03d1 Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Tue, 3 Mar 2020 14:57:03 +0300 Subject: [PATCH] [CJS BE] don't crash when intersection types passed for a reified parameter #KT-37163 Fixed --- .../ir/FirBlackBoxCodegenTestGenerated.java | 15 +++++ .../box/reified/reifiedIntersectionType.kt | 14 +--- .../reifiedIntersectionTypeArgument.kt | 62 +++++++++++++++++ ...fiedIntersectionTypeArgumentCrossModule.kt | 66 +++++++++++++++++++ ...umentWithIntersectionTypeAsTypeArgument.kt | 32 +++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 15 +++++ .../LightAnalysisModeTestGenerated.java | 15 +++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 15 +++++ .../IrJsCodegenBoxTestGenerated.java | 15 +++++ .../semantics/JsCodegenBoxTestGenerated.java | 15 +++++ .../expression/PatternTranslator.java | 41 ++++++++---- .../functions/factories/TypeOfFIF.kt | 23 ++++++- .../kotlin/js/translate/utils/utils.kt | 12 +++- .../js/src/kotlin/reflect/KClassImpl.kt | 13 +++- .../js/src/kotlin/reflect/reflection.kt | 22 +++++-- 15 files changed, 340 insertions(+), 35 deletions(-) create mode 100644 compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt create mode 100644 compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt create mode 100644 compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 94061cea113..1bf95f3d97d 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -25186,6 +25186,21 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/reified/reifiedIntersectionType.kt"); } + @TestMetadata("reifiedIntersectionTypeArgument.kt") + public void testReifiedIntersectionTypeArgument() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt"); + } + + @TestMetadata("reifiedIntersectionTypeArgumentCrossModule.kt") + public void testReifiedIntersectionTypeArgumentCrossModule() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt"); + } + + @TestMetadata("reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt") + public void testReifiedTypeArgumentWithIntersectionTypeAsTypeArgument() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt"); + } + @TestMetadata("safecast.kt") public void testSafecast() throws Exception { runTest("compiler/testData/codegen/box/reified/safecast.kt"); diff --git a/compiler/testData/codegen/box/reified/reifiedIntersectionType.kt b/compiler/testData/codegen/box/reified/reifiedIntersectionType.kt index 27d273cb612..4699e4cd252 100644 --- a/compiler/testData/codegen/box/reified/reifiedIntersectionType.kt +++ b/compiler/testData/codegen/box/reified/reifiedIntersectionType.kt @@ -1,6 +1,6 @@ -// IGNORE_BACKEND: JS // KJS_WITH_FULL_RUNTIME +// KT-37163 // Case that was found in kotlinx.coroutines fun test1() { @@ -20,18 +20,6 @@ public inline fun combine( fun flowOf(value: T): Flow = TODO() interface Flow -// Simplified case - -class In - -inline fun select(x: K, y: K): K = x -interface A -interface B - -fun test2(a: In, b: In) { - select(a, b) -} - fun box(): String { return "OK" } diff --git a/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt b/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt new file mode 100644 index 00000000000..34d2a809514 --- /dev/null +++ b/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt @@ -0,0 +1,62 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// WITH_RUNTIME +// KJS_WITH_FULL_RUNTIME + +// See KT-37163 + +import kotlin.reflect.typeOf + +class In + +interface A +interface B +class C() : A, B + +// TODO check real effects to fix the behavior when we reach consensus +// and to be sure that something is not dropped by optimizations. + +var l = "" +fun log(s: String) { + l += s + ";" +} + +fun consume(a: Any?) {} + +@OptIn(kotlin.ExperimentalStdlibApi::class) +inline fun select(x: K, y: Any): K where K : A, K : B { + log((x is K).toString()) + log((y is K).toString()) + consume(K::class) + log("KClass was created") + consume(typeOf()) + log("KType was created") + consume(Array(1) { x }) + log("array was created") + return x as K +} + +fun test(a: Any, b: Any) { + if (a is A && a is B) { + select(a, b) + } +} + +fun box(): String { + test(C(), object : A, B {}) + test(C(), object : A {}) + test(C(), object : B {}) + test(C(), object {}) + test(C(), Any()) + +// if ( +// l != "true;true;KClass was created;KType was created;array was created;" + +// "true;false;KClass was created;KType was created;array was created;" + +// "true;false;KClass was created;KType was created;array was created;" + +// "true;false;KClass was created;KType was created;array was created;" + +// "true;false;KClass was created;KType was created;array was created;" +// ) { +// return "fail: $l" +// } + + return "OK" +} diff --git a/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt b/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt new file mode 100644 index 00000000000..b60a84c823f --- /dev/null +++ b/compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt @@ -0,0 +1,66 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// WITH_RUNTIME +// KJS_WITH_FULL_RUNTIME + +// See KT-37163 + +// MODULE: m1 +// FILE: a.kt +import kotlin.reflect.typeOf + +class In + +interface A +interface B +class C() : A, B + +// TODO check real effects to fix the behavior when we reach consensus +// and to be sure that something is not dropped by optimizations. + +var l = "" +fun log(s: String) { + l += s + ";" +} + +fun consume(a: Any?) {} + +@OptIn(kotlin.ExperimentalStdlibApi::class) +inline fun select(x: K, y: Any): K where K : A, K : B { + log((x is K).toString()) + log((y is K).toString()) + consume(K::class) + log("KClass was created") + consume(typeOf()) + log("KType was created") + consume(Array(1) { x }) + log("array was created") + return x as K +} + +// MODULE: main(m1) +// FILE: b.kt +fun test(a: Any, b: Any) { + if (a is A && a is B) { + select(a, b) + } +} + +fun box(): String { + test(C(), object : A, B {}) + test(C(), object : A {}) + test(C(), object : B {}) + test(C(), object {}) + test(C(), Any()) + +// if ( +// l != "true;true;KClass was created;KType was created;array was created;" + +// "true;false;KClass was created;KType was created;array was created;" + +// "true;false;KClass was created;KType was created;array was created;" + +// "true;false;KClass was created;KType was created;array was created;" + +// "true;false;KClass was created;KType was created;array was created;" +// ) { +// return "fail: $l" +// } + + return "OK" +} diff --git a/compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt b/compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt new file mode 100644 index 00000000000..c67ac7a683f --- /dev/null +++ b/compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt @@ -0,0 +1,32 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// WITH_RUNTIME +// KJS_WITH_FULL_RUNTIME + +// See KT-37163 + +import kotlin.reflect.typeOf + +class In + +interface A +interface B + +// TODO check real effects to fix the behavior when we reach consensus +// and to be sure that something is not dropped by optimizations. + +@OptIn(kotlin.ExperimentalStdlibApi::class) +inline fun select(x: K, y: K) { + x is K + x as K + K::class + typeOf() + Array(1) { x } +} +fun test() { + select(In(), In()) +} + +fun box(): String { + test() + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 53820e90baf..44292af1444 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -26702,6 +26702,21 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/reified/reifiedIntersectionType.kt"); } + @TestMetadata("reifiedIntersectionTypeArgument.kt") + public void testReifiedIntersectionTypeArgument() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt"); + } + + @TestMetadata("reifiedIntersectionTypeArgumentCrossModule.kt") + public void testReifiedIntersectionTypeArgumentCrossModule() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt"); + } + + @TestMetadata("reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt") + public void testReifiedTypeArgumentWithIntersectionTypeAsTypeArgument() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt"); + } + @TestMetadata("safecast.kt") public void testSafecast() throws Exception { runTest("compiler/testData/codegen/box/reified/safecast.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index b396bb59ebf..22c44214312 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -25519,6 +25519,21 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/reified/reifiedIntersectionType.kt"); } + @TestMetadata("reifiedIntersectionTypeArgument.kt") + public void testReifiedIntersectionTypeArgument() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt"); + } + + @TestMetadata("reifiedIntersectionTypeArgumentCrossModule.kt") + public void testReifiedIntersectionTypeArgumentCrossModule() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt"); + } + + @TestMetadata("reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt") + public void testReifiedTypeArgumentWithIntersectionTypeAsTypeArgument() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt"); + } + @TestMetadata("safecast.kt") public void testSafecast() throws Exception { runTest("compiler/testData/codegen/box/reified/safecast.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index f7b8a0f5892..e02997f1fb4 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -25186,6 +25186,21 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/reified/reifiedIntersectionType.kt"); } + @TestMetadata("reifiedIntersectionTypeArgument.kt") + public void testReifiedIntersectionTypeArgument() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt"); + } + + @TestMetadata("reifiedIntersectionTypeArgumentCrossModule.kt") + public void testReifiedIntersectionTypeArgumentCrossModule() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt"); + } + + @TestMetadata("reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt") + public void testReifiedTypeArgumentWithIntersectionTypeAsTypeArgument() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt"); + } + @TestMetadata("safecast.kt") public void testSafecast() throws Exception { runTest("compiler/testData/codegen/box/reified/safecast.kt"); 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 52bac206c0e..8b0aeed0f8b 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 @@ -20577,6 +20577,21 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reified/reifiedIntersectionType.kt"); } + @TestMetadata("reifiedIntersectionTypeArgument.kt") + public void testReifiedIntersectionTypeArgument() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt"); + } + + @TestMetadata("reifiedIntersectionTypeArgumentCrossModule.kt") + public void testReifiedIntersectionTypeArgumentCrossModule() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt"); + } + + @TestMetadata("reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt") + public void testReifiedTypeArgumentWithIntersectionTypeAsTypeArgument() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt"); + } + @TestMetadata("safecast.kt") public void testSafecast() throws Exception { runTest("compiler/testData/codegen/box/reified/safecast.kt"); 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 225919dae18..87734f59bfc 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 @@ -20637,6 +20637,21 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/reified/reifiedIntersectionType.kt"); } + @TestMetadata("reifiedIntersectionTypeArgument.kt") + public void testReifiedIntersectionTypeArgument() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgument.kt"); + } + + @TestMetadata("reifiedIntersectionTypeArgumentCrossModule.kt") + public void testReifiedIntersectionTypeArgumentCrossModule() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedIntersectionTypeArgumentCrossModule.kt"); + } + + @TestMetadata("reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt") + public void testReifiedTypeArgumentWithIntersectionTypeAsTypeArgument() throws Exception { + runTest("compiler/testData/codegen/box/reified/reifiedTypeArgumentWithIntersectionTypeAsTypeArgument.kt"); + } + @TestMetadata("safecast.kt") public void testSafecast() throws Exception { runTest("compiler/testData/codegen/box/reified/safecast.kt"); diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java index 773bf28fcf8..2a7127bcdc4 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/PatternTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -23,13 +23,22 @@ import org.jetbrains.kotlin.js.translate.general.Translation; import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.ArrayFIF; import org.jetbrains.kotlin.js.translate.intrinsic.functions.factories.TopLevelFIF; import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator; -import org.jetbrains.kotlin.js.translate.utils.*; +import org.jetbrains.kotlin.js.translate.utils.AnnotationsUtils; +import org.jetbrains.kotlin.js.translate.utils.JsAstUtils; +import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; +import org.jetbrains.kotlin.js.translate.utils.UtilsKt; import org.jetbrains.kotlin.name.Name; -import org.jetbrains.kotlin.psi.*; +import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS; +import org.jetbrains.kotlin.psi.KtExpression; +import org.jetbrains.kotlin.psi.KtIsExpression; +import org.jetbrains.kotlin.psi.KtTypeReference; import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.checkers.PrimitiveNumericComparisonInfo; +import org.jetbrains.kotlin.types.IntersectionTypeConstructor; import org.jetbrains.kotlin.types.KotlinType; +import org.jetbrains.kotlin.types.TypeConstructor; +import java.util.Collection; import java.util.Collections; import static org.jetbrains.kotlin.builtins.FunctionTypesKt.isFunctionTypeOrSubtype; @@ -165,14 +174,12 @@ public final class PatternTranslator extends AbstractTranslator { return getIsTypeCheckCallableForReifiedType(typeParameterDescriptor); } - JsExpression result = null; - for (KotlinType upperBound : typeParameterDescriptor.getUpperBounds()) { - JsExpression next = doGetIsTypeCheckCallable(upperBound); - if (next != null) { - result = result != null ? namer().andPredicate(result, next) : next; - } - } - return result; + return getIsTypeCheckForAll(typeParameterDescriptor.getUpperBounds()); + } + + TypeConstructor typeConstructor = type.getConstructor(); + if (typeConstructor instanceof IntersectionTypeConstructor) { + return getIsTypeCheckForAll(typeConstructor.getSupertypes()); } ClassDescriptor referencedClass = DescriptorUtils.getClassDescriptorForType(type); @@ -180,6 +187,18 @@ public final class PatternTranslator extends AbstractTranslator { return namer().isInstanceOf(typeName); } + @Nullable + private JsExpression getIsTypeCheckForAll(Collection typesToCheck) { + JsExpression result = null; + for (KotlinType type : typesToCheck) { + JsExpression next = doGetIsTypeCheckCallable(type); + if (next != null) { + result = result != null ? namer().andPredicate(result, next) : next; + } + } + return result; + } + @Nullable private JsExpression getIsTypeCheckCallableForBuiltin(@NotNull KotlinType type) { if ((isNotNullOrNullableFunctionSupertype(type) || isFunctionTypeOrSubtype(type)) && 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 index 4737823d02e..22b6f4c5059 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -50,7 +50,8 @@ class KTypeConstructor(val context: TranslationContext) { } private fun createSimpleKType(type: SimpleType): JsExpression { - val classifier: ClassifierDescriptor = type.constructor.declarationDescriptor!! + val typeConstructor = type.constructor + val classifier = typeConstructor.declarationDescriptor if (classifier is TypeParameterDescriptor && classifier.isReified) { val kClassName = context.getNameForIntrinsic(SpecialFunction.GET_REIFIED_TYPE_PARAMETER_KTYPE.suggestedName) @@ -64,7 +65,23 @@ class KTypeConstructor(val context: TranslationContext) { return reifiedTypeParameterType } - val kClassifier = createKClassifier(classifier) + val kClassifier = + when { + classifier != null -> { + createKClassifier(classifier) + } + typeConstructor is IntersectionTypeConstructor -> { + val getKClassM = context.getNameForIntrinsic("getKClassM") + val args = JsArrayLiteral( + typeConstructor.supertypes.map { getReferenceToJsClass(it.constructor.declarationDescriptor, context) } + ) + + JsInvocation(getKClassM.makeRef(), args) + } + else -> { + error("Can't get KClass for $type") + } + } val arguments = JsArrayLiteral(type.arguments.map { createKTypeProjection(it) }) val isMarkedNullable = JsBooleanLiteral(type.isMarkedNullable) return callHelperFunction( 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 58e7f8d71c3..81879f828e1 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 @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -40,7 +40,6 @@ 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 @@ -128,10 +127,17 @@ fun List.splitToRanges(classifier: (T) -> S): List, S>> { } fun getReferenceToJsClass(type: KotlinType, context: TranslationContext): JsExpression = - getReferenceToJsClass(type.constructor.declarationDescriptor, context).also { + getReferenceToJsClassOrArray(type, context).also { it.kType = KTypeConstructor(context).createKType(type) } +fun getReferenceToJsClassOrArray(type: KotlinType, context: TranslationContext): JsExpression { + val classifierDescriptor = type.constructor.declarationDescriptor + ?: return JsArrayLiteral(type.constructor.supertypes.map { getReferenceToJsClass(it.constructor.declarationDescriptor, context) }) + + return getReferenceToJsClass(classifierDescriptor, context) +} + fun getReferenceToJsClass(classifierDescriptor: ClassifierDescriptor?, context: TranslationContext): JsExpression { return when (classifierDescriptor) { is ClassDescriptor -> { diff --git a/libraries/stdlib/js/src/kotlin/reflect/KClassImpl.kt b/libraries/stdlib/js/src/kotlin/reflect/KClassImpl.kt index 027adba3999..8b77c5ad315 100644 --- a/libraries/stdlib/js/src/kotlin/reflect/KClassImpl.kt +++ b/libraries/stdlib/js/src/kotlin/reflect/KClassImpl.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -62,5 +62,16 @@ internal object NothingKClassImpl : KClassImpl(js("Object")) { override fun equals(other: Any?): Boolean = other === this + override fun hashCode(): Int = 0 +} + +internal class ErrorKClass : KClass { + override val simpleName: String? get() = error("Unknown simpleName for ErrorKClass") + override val qualifiedName: String? get() = error("Unknown qualifiedName for ErrorKClass") + + override fun isInstance(value: Any?): Boolean = error("Can's check isInstance on ErrorKClass") + + override fun equals(other: Any?): Boolean = other === this + override fun hashCode(): Int = 0 } \ 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 cdddf7c173f..5d61748af72 100644 --- a/libraries/stdlib/js/src/kotlin/reflect/reflection.kt +++ b/libraries/stdlib/js/src/kotlin/reflect/reflection.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -9,7 +9,20 @@ import kotlin.reflect.* import kotlin.reflect.js.internal.* @JsName("getKClass") -internal fun getKClass(jClass: JsClass): KClass = getOrCreateKClass(jClass) +internal fun getKClass(jClass: Any /* JsClass | Array> */): KClass { + return if (js("Array").isArray(jClass)) { + getKClassM(jClass.unsafeCast>>()) + } else { + getKClass1(jClass.unsafeCast>()) + } +} + +@JsName("getKClassM") +internal fun getKClassM(jClasses: Array>): KClass = when (jClasses.size) { + 1 -> getKClass1(jClasses[0]) + 0 -> NothingKClassImpl.unsafeCast>() + else -> ErrorKClass().unsafeCast>() +} @JsName("getKClassFromExpression") internal fun getKClassFromExpression(e: T): KClass = @@ -37,7 +50,7 @@ internal fun getKClassFromExpression(e: T): KClass = constructor === js("Error") -> PrimitiveClasses.throwableClass else -> { val jsClass: JsClass = constructor - getOrCreateKClass(jsClass) + getKClass1(jsClass) } } } @@ -45,7 +58,8 @@ internal fun getKClassFromExpression(e: T): KClass = } }.unsafeCast>() -private fun getOrCreateKClass(jClass: JsClass): KClass { +@JsName("getKClass1") +internal fun getKClass1(jClass: JsClass): KClass { if (jClass === js("String")) return PrimitiveClasses.stringClass.unsafeCast>() val metadata = jClass.asDynamic().`$metadata$`