JS: fix class literal expression with primitive classes. See KT-16545

This commit is contained in:
Alexey Andreev
2017-03-01 20:04:50 +03:00
parent 8567db10b5
commit 723c9be5a0
6 changed files with 96 additions and 1 deletions
+6
View File
@@ -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.
+6 -1
View File
@@ -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);
}
@@ -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);
}
+49
View File
@@ -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)
}