JS: fix class literal expression with primitive classes. See KT-16545
This commit is contained in:
@@ -64,6 +64,12 @@ Kotlin.Long = function(low, high) {
|
||||
this.high_ = high | 0; // force into 32 signed bits.
|
||||
};
|
||||
|
||||
Kotlin.Long.$metadata$ = {
|
||||
kind: "class",
|
||||
simpleName: "Long",
|
||||
interfaces:[]
|
||||
};
|
||||
|
||||
|
||||
// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the
|
||||
// from* methods on which they depend.
|
||||
|
||||
@@ -35,7 +35,12 @@ external fun <T : Any> jsClass(): JsClass<T>
|
||||
|
||||
@Deprecated("Use class literal and extension property `js` instead.", replaceWith = ReplaceWith("this::class.js"), level = DeprecationLevel.WARNING)
|
||||
val <T : Any> T.jsClass: JsClass<T>
|
||||
get() = js("Object").getPrototypeOf(this).constructor
|
||||
get() = when (jsTypeOf(this)) {
|
||||
"string" -> js("String")
|
||||
"number" -> js("Number")
|
||||
"boolean" -> js("Boolean")
|
||||
else -> js("Object").getPrototypeOf(this).constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a constructor reference for the given `KClass`.
|
||||
|
||||
@@ -6883,6 +6883,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/reflection/kClassToAndFromJsClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("primitives.kt")
|
||||
public void testPrimitives() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/reflection/primitives.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("js/js.translator/testData/box/regression")
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.hash.LinkedHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.FunctionTypesKt;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
@@ -47,6 +48,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallsKt;
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
|
||||
|
||||
import java.util.*;
|
||||
@@ -247,9 +249,32 @@ public final class StaticContext {
|
||||
private JsExpression buildQualifiedExpression(@NotNull DeclarationDescriptor descriptor) {
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
|
||||
KotlinType type = classDescriptor.getDefaultType();
|
||||
if (KotlinBuiltIns.isAny(classDescriptor)) {
|
||||
return pureFqn("Object", null);
|
||||
}
|
||||
else if (KotlinBuiltIns.isInt(type) || KotlinBuiltIns.isShort(type) || KotlinBuiltIns.isByte(type) ||
|
||||
KotlinBuiltIns.isFloat(type) || KotlinBuiltIns.isDouble(type)) {
|
||||
return pureFqn("Number", null);
|
||||
}
|
||||
else if (KotlinBuiltIns.isLong(type)) {
|
||||
return pureFqn("Long", Namer.kotlinObject());
|
||||
}
|
||||
else if (KotlinBuiltIns.isChar(type)) {
|
||||
return pureFqn("BoxedChar", Namer.kotlinObject());
|
||||
}
|
||||
else if (KotlinBuiltIns.isString(type)) {
|
||||
return pureFqn("String", null);
|
||||
}
|
||||
else if (KotlinBuiltIns.isBoolean(type)) {
|
||||
return pureFqn("Boolean", null);
|
||||
}
|
||||
else if (KotlinBuiltIns.isArrayOrPrimitiveArray(classDescriptor)) {
|
||||
return pureFqn("Array", null);
|
||||
}
|
||||
else if (FunctionTypesKt.isBuiltinFunctionalType(type)) {
|
||||
return pureFqn("Function", null);
|
||||
}
|
||||
else if (TypeUtilsKt.isThrowable(classDescriptor.getDefaultType())) {
|
||||
return pureFqn("Error", null);
|
||||
}
|
||||
|
||||
+4
@@ -238,6 +238,10 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
|
||||
|
||||
if (lhs instanceof DoubleColonLHS.Expression && !((DoubleColonLHS.Expression) lhs).isObjectQualifier()) {
|
||||
JsExpression receiver = translateAsExpression(receiverExpression, context);
|
||||
KotlinType type = context.bindingContext().getType(receiverExpression);
|
||||
if (type != null && KotlinBuiltIns.isChar(type)) {
|
||||
receiver = JsAstUtils.charToBoxedChar(receiver);
|
||||
}
|
||||
return new JsInvocation(context.namer().kotlin(GET_KCLASS_FROM_EXPRESSION), receiver);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
fun box(): String {
|
||||
check(js("Object"), Any::class)
|
||||
check(js("String"), String::class)
|
||||
check(js("Boolean"), Boolean::class)
|
||||
check(js("Error"), Throwable::class)
|
||||
check(js("Array"), Array<Any>::class)
|
||||
check(js("Function"), Function0::class)
|
||||
|
||||
check(js("Number"), Byte::class)
|
||||
check(js("Number"), Short::class)
|
||||
check(js("Number"), Int::class)
|
||||
check(js("Number"), Float::class)
|
||||
check(js("Number"), Double::class)
|
||||
|
||||
check(js("Object"), Any())
|
||||
check(js("String"), "*")
|
||||
check(js("Boolean"), true)
|
||||
check(js("Error"), Throwable())
|
||||
check(js("Array"), arrayOf(1, 2, 3))
|
||||
check(js("Function"), { x: Int -> x })
|
||||
|
||||
check(js("Number"), 23.toByte())
|
||||
check(js("Number"), 23.toShort())
|
||||
check(js("Number"), 23)
|
||||
check(js("Number"), 23.0F)
|
||||
check(js("Number"), 23.0)
|
||||
|
||||
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("KClassImpl", 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}")
|
||||
}
|
||||
|
||||
private fun check(nativeClass: dynamic, value: Any) {
|
||||
check(nativeClass, value::class)
|
||||
}
|
||||
Reference in New Issue
Block a user