diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java index d9440d56873..4ece325fe89 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget; import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.incremental.components.LookupLocation; +import org.jetbrains.kotlin.incremental.components.NoLookupLocation; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqNameUnsafe; import org.jetbrains.kotlin.name.Name; @@ -586,11 +587,10 @@ public class DescriptorUtils { @Nullable public static FunctionDescriptor getFunctionByNameOrNull(@NotNull MemberScope scope, @NotNull Name name) { - Collection functions = scope.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS, - MemberScope.Companion.getALL_NAME_FILTER()); - for (DeclarationDescriptor d : functions) { - if (d instanceof FunctionDescriptor && name.equals(d.getOriginal().getName())) { - return (FunctionDescriptor) d; + Collection functions = scope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND); + for (SimpleFunctionDescriptor d : functions) { + if (name.equals(d.getOriginal().getName())) { + return d; } } @@ -599,11 +599,10 @@ public class DescriptorUtils { @NotNull public static PropertyDescriptor getPropertyByName(@NotNull MemberScope scope, @NotNull Name name) { - Collection callables = scope.getContributedDescriptors( - DescriptorKindFilter.CALLABLES, MemberScope.Companion.getALL_NAME_FILTER()); - for (DeclarationDescriptor d : callables) { - if (d instanceof PropertyDescriptor && name.equals(d.getOriginal().getName())) { - return (PropertyDescriptor) d; + Collection properties = scope.getContributedVariables(name, NoLookupLocation.FROM_BACKEND); + for (PropertyDescriptor d : properties) { + if (name.equals(d.getOriginal().getName())) { + return d; } } diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/config/JsConfig.java b/js/js.frontend/src/org/jetbrains/kotlin/js/config/JsConfig.java index fed0a6f36b5..77ce9f7cfa5 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/config/JsConfig.java +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/config/JsConfig.java @@ -139,6 +139,12 @@ public class JsConfig { return getConfiguration().getList(JSConfigurationKeys.FRIEND_PATHS); } + public boolean isAtLeast(@NotNull LanguageVersion expected) { + LanguageVersion actual = CommonConfigurationKeysKt.getLanguageVersionSettings(configuration).getLanguageVersion(); + return actual.getMajor() > expected.getMajor() || + actual.getMajor() == expected.getMajor() && actual.getMinor() >= expected.getMinor(); + } + public static abstract class Reporter { public void error(@NotNull String message) { /*Do nothing*/ } diff --git a/js/js.libraries/src/reflect/KClassImpl.kt b/js/js.libraries/src/reflect/KClassImpl.kt index d32d03d30f2..c556b4ade24 100644 --- a/js/js.libraries/src/reflect/KClassImpl.kt +++ b/js/js.libraries/src/reflect/KClassImpl.kt @@ -18,17 +18,9 @@ package kotlin.reflect.js.internal import kotlin.reflect.* -internal class KClassImpl( - internal val jClass: JsClass +internal abstract class KClassImpl( + internal open val jClass: JsClass ) : KClass { - - private val metadata = jClass.asDynamic().`$metadata$` - // TODO: use FQN - private val hashCode = simpleName?.hashCode() ?: 0 - - override val simpleName: String? - get() = metadata?.simpleName - override val annotations: List get() = TODO() override val constructors: Collection> @@ -66,16 +58,49 @@ internal class KClassImpl( return other is KClassImpl<*> && jClass == other.jClass } - override fun hashCode(): Int { - return hashCode - } - - override fun isInstance(value: Any?): Boolean { - return js("Kotlin").isType(value, jClass) - } + // TODO: use FQN + override fun hashCode(): Int = simpleName?.hashCode() ?: 0 override fun toString(): String { // TODO: use FQN return "class $simpleName" } } + +internal class SimpleKClassImpl(jClass: JsClass) : KClassImpl(jClass) { + override val simpleName: String? = jClass.asDynamic().`$metadata$`?.simpleName.unsafeCast() + + override fun isInstance(value: Any?): Boolean { + return js("Kotlin").isType(value, jClass) + } +} + +internal class PrimitiveKClassImpl( + jClass: JsClass, + private val givenSimpleName: String, + private val isInstanceFunction: (Any?) -> Boolean +) : KClassImpl(jClass) { + override fun equals(other: Any?): Boolean { + if (other !is PrimitiveKClassImpl<*>) return false + return super.equals(other) && givenSimpleName == other.givenSimpleName + } + + override val simpleName: String? get() = givenSimpleName + + override fun isInstance(value: Any?): Boolean { + return isInstanceFunction(value) + } +} + +internal object NothingKClassImpl : KClassImpl(js("Object")) { + override val simpleName: String = "Nothing" + + override fun isInstance(value: Any?): Boolean = false + + override val jClass: JsClass + get() = throw UnsupportedOperationException("There's no native JS class for Nothing type") + + override fun equals(other: Any?): Boolean = other === this + + override fun hashCode(): Int = 0 +} \ No newline at end of file diff --git a/js/js.libraries/src/reflect/primitives.kt b/js/js.libraries/src/reflect/primitives.kt new file mode 100644 index 00000000000..8eca2eb8730 --- /dev/null +++ b/js/js.libraries/src/reflect/primitives.kt @@ -0,0 +1,94 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.reflect.js.internal + +import kotlin.js.JsClass + +@JsName("PrimitiveClasses") +internal object PrimitiveClasses { + @JsName("anyClass") + val anyClass = PrimitiveKClassImpl(js("Object").unsafeCast>(), "Any", { it is Any }) + + @JsName("numberClass") + val numberClass = PrimitiveKClassImpl(js("Number").unsafeCast>(), "Number", { it is Number }) + + @JsName("nothingClass") + val nothingClass = NothingKClassImpl + + @JsName("booleanClass") + val booleanClass = PrimitiveKClassImpl(js("Boolean").unsafeCast>(), "Boolean", { it is Boolean }) + + @JsName("byteClass") + val byteClass = PrimitiveKClassImpl(js("Number").unsafeCast>(), "Byte", { it is Byte }) + + @JsName("shortClass") + val shortClass = PrimitiveKClassImpl(js("Number").unsafeCast>(), "Short", { it is Short }) + + @JsName("intClass") + val intClass = PrimitiveKClassImpl(js("Number").unsafeCast>(), "Int", { it is Int }) + + @JsName("floatClass") + val floatClass = PrimitiveKClassImpl(js("Number").unsafeCast>(), "Float", { it is Float }) + + @JsName("doubleClass") + val doubleClass = PrimitiveKClassImpl(js("Number").unsafeCast>(), "Double", { it is Double }) + + @JsName("arrayClass") + val arrayClass = PrimitiveKClassImpl(js("Array").unsafeCast>>(), "Array", { it is Array<*> }) + + @JsName("stringClass") + val stringClass = PrimitiveKClassImpl(js("String").unsafeCast>(), "String", { it is String }) + + @JsName("throwableClass") + val throwableClass = PrimitiveKClassImpl(js("Error").unsafeCast>(), "Throwable", { it is Throwable }) + + @JsName("booleanArrayClass") + val booleanArrayClass = PrimitiveKClassImpl(js("Array").unsafeCast>(), "BooleanArray", { it is BooleanArray }) + + @JsName("charArrayClass") + val charArrayClass = PrimitiveKClassImpl(js("Uint16Array").unsafeCast>(), "CharArray", { it is CharArray }) + + @JsName("byteArrayClass") + val byteArrayClass = PrimitiveKClassImpl(js("Int8Array").unsafeCast>(), "ByteArray", { it is ByteArray }) + + @JsName("shortArrayClass") + val shortArrayClass = PrimitiveKClassImpl(js("Int16Array").unsafeCast>(), "ShortArray", { it is ShortArray }) + + @JsName("intArrayClass") + val intArrayClass = PrimitiveKClassImpl(js("Int32Array").unsafeCast>(), "IntArray", { it is IntArray }) + + @JsName("longArrayClass") + val longArrayClass = PrimitiveKClassImpl(js("Array").unsafeCast>(), "LongArray", { it is LongArray }) + + @JsName("floatArrayClass") + val floatArrayClass = PrimitiveKClassImpl(js("Float32Array").unsafeCast>(), "FloatArray", { it is FloatArray }) + + @JsName("doubleArrayClass") + val doubleArrayClass = PrimitiveKClassImpl(js("Float64Array").unsafeCast>(), "DoubleArray", { it is DoubleArray }) + + @JsName("functionClass") + fun functionClass(arity: Int): KClassImpl { + return functionClasses.get(arity) ?: run { + val result = PrimitiveKClassImpl(js("Function").unsafeCast>(), "Function$arity", + { jsTypeOf(it) === "function" && it.asDynamic().length == arity }) + functionClasses.asDynamic()[arity] = result + result + } + } +} + +private val functionClasses = arrayOfNulls>(0) \ No newline at end of file diff --git a/js/js.libraries/src/reflect/reflection.kt b/js/js.libraries/src/reflect/reflection.kt index 00bbe42f367..ad003eb1c7d 100644 --- a/js/js.libraries/src/reflect/reflection.kt +++ b/js/js.libraries/src/reflect/reflection.kt @@ -17,19 +17,52 @@ // a package is omitted to get declarations directly under the module import kotlin.reflect.KClass -import kotlin.reflect.js.internal.KClassImpl +import kotlin.reflect.js.internal.* @JsName("getKClass") internal fun getKClass(jClass: JsClass): KClass = getOrCreateKClass(jClass) @JsName("getKClassFromExpression") -internal fun getKClassFromExpression(e: T): KClass = getOrCreateKClass(e.jsClass) +internal fun getKClassFromExpression(e: T): KClass = + when (jsTypeOf(e)) { + "string" -> PrimitiveClasses.stringClass + "number" -> if (js("e | 0") === e) PrimitiveClasses.intClass else PrimitiveClasses.doubleClass + "boolean" -> PrimitiveClasses.booleanClass + "function" -> PrimitiveClasses.functionClass(e.asDynamic().length) + else -> { + when { + e is BooleanArray -> PrimitiveClasses.booleanArrayClass + e is CharArray -> PrimitiveClasses.charArrayClass + e is ByteArray -> PrimitiveClasses.byteArrayClass + e is ShortArray -> PrimitiveClasses.shortArrayClass + e is IntArray -> PrimitiveClasses.intArrayClass + e is LongArray -> PrimitiveClasses.longArrayClass + e is FloatArray -> PrimitiveClasses.floatArrayClass + e is DoubleArray -> PrimitiveClasses.doubleArrayClass + e is KClass<*> -> KClass::class + e is Array<*> -> PrimitiveClasses.arrayClass + else -> { + val constructor = js("Object").getPrototypeOf(e).constructor + when { + constructor === js("Object") -> PrimitiveClasses.anyClass + constructor === js("Error") -> PrimitiveClasses.throwableClass + else -> { + val jsClass: JsClass = constructor + getOrCreateKClass(jsClass) + } + } + } + } + } + }.unsafeCast>() private fun getOrCreateKClass(jClass: JsClass): KClass { + if (jClass === js("String")) return PrimitiveClasses.stringClass.unsafeCast>() + val metadata = jClass.asDynamic().`$metadata$` return if (metadata != null) { if (metadata.`$kClass$` == null) { - val kClass = KClassImpl(jClass) + val kClass = SimpleKClassImpl(jClass) metadata.`$kClass$` = kClass kClass } @@ -38,7 +71,7 @@ private fun getOrCreateKClass(jClass: JsClass): KClass { } } else { - KClassImpl(jClass) + SimpleKClassImpl(jClass) } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index 9e92b830d3d..51387ee1288 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -7441,6 +7441,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/reflection/primitives.kt"); doTest(fileName); } + + @TestMetadata("primitives-12.kt") + public void testPrimitives_12() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/reflection/primitives-12.kt"); + doTest(fileName); + } } @TestMetadata("js/js.translator/testData/box/regression") diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java index 9cc0169bad2..74bc5e8116a 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/expression/ExpressionVisitor.java @@ -16,10 +16,14 @@ package org.jetbrains.kotlin.js.translate.expression; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.builtins.KotlinBuiltIns; +import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor; +import org.jetbrains.kotlin.config.LanguageVersion; import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention; @@ -40,10 +44,14 @@ import org.jetbrains.kotlin.js.translate.utils.TranslationUtils; import org.jetbrains.kotlin.js.translate.utils.UtilsKt; import org.jetbrains.kotlin.js.translate.utils.mutator.CoercionMutator; import org.jetbrains.kotlin.js.translate.utils.mutator.LastExpressionMutator; +import org.jetbrains.kotlin.name.ClassId; +import org.jetbrains.kotlin.name.FqName; +import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContextUtils; +import org.jetbrains.kotlin.resolve.DescriptorUtils; import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; @@ -54,14 +62,15 @@ import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.expressions.DoubleColonLHS; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import static org.jetbrains.kotlin.descriptors.FindClassInModuleKt.findClassAcrossModuleDependencies; import static org.jetbrains.kotlin.js.translate.context.Namer.*; import static org.jetbrains.kotlin.js.translate.general.Translation.translateAsExpression; import static org.jetbrains.kotlin.js.translate.utils.BindingUtils.*; import static org.jetbrains.kotlin.js.translate.utils.ErrorReportingUtils.message; -import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.convertToStatement; -import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.newVar; +import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.*; import static org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getReceiverParameterForDeclaration; import static org.jetbrains.kotlin.js.translate.utils.TranslationUtils.translateInitializerForProperty; import static org.jetbrains.kotlin.resolve.BindingContext.*; @@ -72,6 +81,8 @@ import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFun import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral; public final class ExpressionVisitor extends TranslatorVisitor { + private static final FqName primitiveClassesFqName = new FqName("kotlin.reflect.js.internal.PrimitiveClasses"); + @Override protected JsNode emptyResult(@NotNull TranslationContext context) { return new JsNullLiteral(); @@ -260,12 +271,85 @@ public final class ExpressionVisitor extends TranslatorVisitor { if (lhs instanceof DoubleColonLHS.Expression && !((DoubleColonLHS.Expression) lhs).isObjectQualifier()) { JsExpression receiver = translateAsExpression(receiverExpression, context); receiver = TranslationUtils.coerce(context, receiver, context.getCurrentModule().getBuiltIns().getAnyType()); + if (isPrimitiveClassLiteral(lhs.getType())) { + JsExpression primitiveExpression = getPrimitiveClass(context, lhs.getType()); + if (primitiveExpression != null) { + return JsAstUtils.newSequence(Arrays.asList(receiver, primitiveExpression)); + } + } return new JsInvocation(context.namer().kotlin(GET_KCLASS_FROM_EXPRESSION), receiver); } + JsExpression primitiveExpression = getPrimitiveClass(context, lhs.getType()); + if (primitiveExpression != null) return primitiveExpression; return new JsInvocation(context.getReferenceToIntrinsic(GET_KCLASS), UtilsKt.getReferenceToJsClass(lhs.getType(), context)); } + private static JsExpression getPrimitiveClass(@NotNull TranslationContext context, @NotNull KotlinType type) { + if (!context.getConfig().isAtLeast(LanguageVersion.KOTLIN_1_2) || findPrimitiveClassesObject(context) == null) return null; + + ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); + if (descriptor instanceof ClassDescriptor) { + FqName fqName = DescriptorUtilsKt.getFqNameSafe(descriptor); + switch (fqName.asString()) { + case "kotlin.Boolean": + case "kotlin.Byte": + case "kotlin.Short": + case "kotlin.Int": + case "kotlin.Float": + case "kotlin.Double": + case "kotlin.String": + case "kotlin.Array": + case "kotlin.Any": + case "kotlin.Throwable": + case "kotlin.Number": + case "kotlin.Nothing": + case "kotlin.BooleanArray": + case "kotlin.CharArray": + case "kotlin.ByteArray": + case "kotlin.ShortArray": + case "kotlin.IntArray": + case "kotlin.LongArray": + case "kotlin.FloatArray": + case "kotlin.DoubleArray": + return getKotlinPrimitiveClassRef(context, StringUtil.decapitalize(fqName.shortName().asString()) + "Class"); + + default: { + if (descriptor instanceof FunctionClassDescriptor) { + FunctionClassDescriptor functionClassDescriptor = (FunctionClassDescriptor) descriptor; + if (functionClassDescriptor.getFunctionKind() == FunctionClassDescriptor.Kind.Function) { + ClassDescriptor primitivesObject = findPrimitiveClassesObject(context); + assert primitivesObject != null; + FunctionDescriptor function = DescriptorUtils.getFunctionByName( + primitivesObject.getUnsubstitutedMemberScope(), Name.identifier("functionClass")); + JsExpression functionRef = pureFqn(context.getInlineableInnerNameForDescriptor(function), null); + return new JsInvocation(functionRef, new JsIntLiteral(functionClassDescriptor.getArity())); + } + } + break; + } + } + } + return null; + } + + @NotNull + private static JsExpression getKotlinPrimitiveClassRef(@NotNull TranslationContext context, @NotNull String name) { + ClassDescriptor primitivesObject = findPrimitiveClassesObject(context); + assert primitivesObject != null; + PropertyDescriptor property = DescriptorUtils.getPropertyByName( + primitivesObject.getUnsubstitutedMemberScope(), Name.identifier(name)); + return pureFqn(context.getInlineableInnerNameForDescriptor(property), null); + } + + private static boolean isPrimitiveClassLiteral(@NotNull KotlinType type) { + return KotlinBuiltIns.isPrimitiveType(type) || KotlinBuiltIns.isArray(type) || KotlinBuiltIns.isPrimitiveArray(type); + } + + @Nullable + private static ClassDescriptor findPrimitiveClassesObject(@NotNull TranslationContext context) { + return findClassAcrossModuleDependencies(context.getCurrentModule(), ClassId.topLevel(primitiveClassesFqName)); + } @Override @NotNull diff --git a/js/js.translator/testData/box/char/charEquals.kt b/js/js.translator/testData/box/char/charEquals.kt index 241b5b67e5b..3e42df28aa6 100644 --- a/js/js.translator/testData/box/char/charEquals.kt +++ b/js/js.translator/testData/box/char/charEquals.kt @@ -1,4 +1,4 @@ -// EXPECTED_REACHABLE_NODES: 994 +// EXPECTED_REACHABLE_NODES: 1094 package foo class A diff --git a/js/js.translator/testData/box/crossModuleRef/inlineJsModule.kt b/js/js.translator/testData/box/crossModuleRef/inlineJsModule.kt index 8f78cbca4c4..dd200a21098 100644 --- a/js/js.translator/testData/box/crossModuleRef/inlineJsModule.kt +++ b/js/js.translator/testData/box/crossModuleRef/inlineJsModule.kt @@ -1,4 +1,4 @@ -// EXPECTED_REACHABLE_NODES: 1070 +// EXPECTED_REACHABLE_NODES: 1181 // MODULE: lib1 // FILE: lib1.js define("lib1", [], function() { diff --git a/js/js.translator/testData/box/crossModuleRef/inlineJsModuleNonIdentifier.kt b/js/js.translator/testData/box/crossModuleRef/inlineJsModuleNonIdentifier.kt index 978af086b69..f1665c8ece5 100644 --- a/js/js.translator/testData/box/crossModuleRef/inlineJsModuleNonIdentifier.kt +++ b/js/js.translator/testData/box/crossModuleRef/inlineJsModuleNonIdentifier.kt @@ -1,4 +1,4 @@ -// EXPECTED_REACHABLE_NODES: 1072 +// EXPECTED_REACHABLE_NODES: 1181 // MODULE: lib-1 // FILE: lib-1.js define("lib-1", [], function() { diff --git a/js/js.translator/testData/box/incremental/coroutines.kt b/js/js.translator/testData/box/incremental/coroutines.kt index fa8b31ea689..e60263b9a76 100644 --- a/js/js.translator/testData/box/incremental/coroutines.kt +++ b/js/js.translator/testData/box/incremental/coroutines.kt @@ -1,4 +1,4 @@ -// EXPECTED_REACHABLE_NODES: 1055 +// EXPECTED_REACHABLE_NODES: 1172 // FILE: a.kt // WITH_RUNTIME import kotlin.coroutines.experimental.* diff --git a/js/js.translator/testData/box/reflection/external.kt b/js/js.translator/testData/box/reflection/external.kt index f632f21128d..07060d59df5 100644 --- a/js/js.translator/testData/box/reflection/external.kt +++ b/js/js.translator/testData/box/reflection/external.kt @@ -1,4 +1,4 @@ -// EXPECTED_REACHABLE_NODES: 997 +// EXPECTED_REACHABLE_NODES: 1099 external class A external object O diff --git a/js/js.translator/testData/box/reflection/primitives-12.kt b/js/js.translator/testData/box/reflection/primitives-12.kt new file mode 100644 index 00000000000..1c3840a84d0 --- /dev/null +++ b/js/js.translator/testData/box/reflection/primitives-12.kt @@ -0,0 +1,88 @@ +// EXPECTED_REACHABLE_NODES: 1119 +// LANGUAGE_VERSION: 1.2 +import kotlin.reflect.KClass + +fun box(): String { + check(js("Object"), "Any", Any::class) + check(js("String"), "String", String::class) + check(js("Boolean"), "Boolean", Boolean::class) + check(js("Error"), "Throwable", Throwable::class) + check(js("Array"), "Array", Array::class) + check(js("Function"), "Function0", Function0::class) + check(js("Function"), "Function1", Function1::class) + + check(js("Number"), "Byte", Byte::class) + check(js("Number"), "Short", Short::class) + check(js("Number"), "Int", Int::class) + check(js("Number"), "Float", Float::class) + check(js("Number"), "Double", Double::class) + check(js("Number"), "Number", Number::class) + + check(js("Array"), "BooleanArray", BooleanArray::class) + check(js("Uint16Array"), "CharArray", CharArray::class) + check(js("Int8Array"), "ByteArray", ByteArray::class) + check(js("Int16Array"), "ShortArray", ShortArray::class) + check(js("Int32Array"), "IntArray", IntArray::class) + check(js("Array"), "LongArray", LongArray::class) + check(js("Float32Array"), "FloatArray", FloatArray::class) + check(js("Float64Array"), "DoubleArray", DoubleArray::class) + + check(js("Object"), "Any", Any()) + check(js("String"), "String", "*") + check(js("Boolean"), "Boolean", true) + check(js("Error"), "Throwable", Throwable()) + check(js("Array"), "Array", arrayOf(1, 2, 3)) + check(js("Function"), "Function0", { -> 23 }) + check(js("Function"), "Function1", { x: Int -> x }) + + check(js("Array"), "BooleanArray", booleanArrayOf()) + check(js("Uint16Array"), "CharArray", charArrayOf()) + check(js("Int8Array"), "ByteArray", byteArrayOf()) + check(js("Int16Array"), "ShortArray", shortArrayOf()) + check(js("Int32Array"), "IntArray", intArrayOf()) + check(js("Array"), "LongArray", longArrayOf()) + check(js("Float32Array"), "FloatArray", floatArrayOf()) + check(js("Float64Array"), "DoubleArray", doubleArrayOf()) + + check(js("Number"), "Int", 23.toByte()) + check(js("Number"), "Int", 23.toShort()) + check(js("Number"), "Int", 23) + check(js("Number"), "Int", 23.0) + check(js("Number"), "Double", 23.1F) + check(js("Number"), "Double", 23.2) + + check(js("Number"), "Int", Int::class) + check(js("Number"), "Byte", Byte::class) + check(js("Number"), "Double", Double::class) + + assertEquals("Long", Long::class.simpleName) + assertEquals("Long", 23L::class.simpleName) + assertEquals("BoxedChar", Char::class.simpleName) + assertEquals("BoxedChar", '@'::class.simpleName) + assertEquals("RuntimeException", RuntimeException::class.simpleName) + assertEquals("RuntimeException", RuntimeException()::class.simpleName) + assertEquals("KClass", KClass::class.simpleName) + assertEquals("KClass", Any::class::class.simpleName) + assertEquals("KClass", Map::class::class.simpleName) + + try { + assertEquals("Nothing", Nothing::class.simpleName) + Nothing::class.js + fail("Exception expected when trying to get JS class for Nothing type") + } + catch (e: UnsupportedOperationException) { + // It's OK + } + + return "OK" +} + +private fun check(nativeClass: dynamic, simpleName: String, c: KClass<*>) { + assertEquals(simpleName, c.simpleName, "Simple name of class has unexpected value") + assertEquals(nativeClass, c.js, "Kotlin class does not correspond native class ${nativeClass.name}") +} + +private fun check(nativeClass: dynamic, simpleName: String, value: Any) { + check(nativeClass, simpleName, value::class) + assertTrue(value::class.isInstance(value), "isInstance should return true for $simpleName") +} \ No newline at end of file diff --git a/js/js.translator/testData/box/reflection/primitives.kt b/js/js.translator/testData/box/reflection/primitives.kt index 337235c6bd7..dec20551521 100644 --- a/js/js.translator/testData/box/reflection/primitives.kt +++ b/js/js.translator/testData/box/reflection/primitives.kt @@ -1,4 +1,5 @@ // EXPECTED_REACHABLE_NODES: 1003 +// LANGUAGE_VERSION: 1.1 import kotlin.reflect.KClass fun box(): String { @@ -35,13 +36,12 @@ fun box(): String { assertEquals("RuntimeException", RuntimeException::class.simpleName) assertEquals("RuntimeException", RuntimeException()::class.simpleName) assertEquals("KClass", KClass::class.simpleName) - assertEquals("KClassImpl", Any::class::class.simpleName) + assertEquals("KClass", Any::class::class.simpleName) return "OK" } private fun check(nativeClass: dynamic, c: KClass<*>) { - assertEquals(null, c.simpleName, "Simple name of native class ${nativeClass.name} must be null") assertEquals(nativeClass, c.js, "Kotlin class does not correspond native class ${nativeClass.name}") }