JS: fix reified T::class for primitive T (e.g. Int) (KT-32215 fixed)

This commit is contained in:
Anton Bannykh
2019-06-27 17:28:41 +03:00
parent d972d50296
commit fadeac083f
17 changed files with 163 additions and 12 deletions
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention;
import org.jetbrains.kotlin.js.backend.ast.*;
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
import org.jetbrains.kotlin.js.backend.ast.metadata.SpecialFunction;
import org.jetbrains.kotlin.js.naming.NameSuggestion;
import org.jetbrains.kotlin.js.translate.context.TranslationContext;
import org.jetbrains.kotlin.js.translate.declaration.ClassTranslator;
@@ -288,11 +289,11 @@ public final class ExpressionVisitor extends TranslatorVisitor<JsNode> {
public static JsExpression getObjectKClass(@NotNull TranslationContext context, @Nullable ClassifierDescriptor descriptor) {
JsExpression primitiveExpression = getPrimitiveClass(context, descriptor);
if (primitiveExpression != null) return primitiveExpression;
return new JsInvocation(context.getReferenceToIntrinsic(GET_KCLASS), UtilsKt.getReferenceToJsClass(descriptor, context));
return new JsInvocation(context.getNameForSpecialFunction(SpecialFunction.GET_KCLASS).makeRef(), UtilsKt.getReferenceToJsClass(descriptor, context));
}
@Nullable
private static JsExpression getPrimitiveClass(@NotNull TranslationContext context, @Nullable ClassifierDescriptor classifierDescriptor) {
public static JsExpression getPrimitiveClass(@NotNull TranslationContext context, @Nullable ClassifierDescriptor classifierDescriptor) {
if (!context.getConfig().isAtLeast(LanguageVersion.KOTLIN_1_2) || findPrimitiveClassesObject(context) == null) return null;
if (!(classifierDescriptor instanceof ClassDescriptor)) return null;
ClassDescriptor descriptor = (ClassDescriptor) classifierDescriptor;
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.js.backend.ast.metadata.*
import org.jetbrains.kotlin.js.translate.callTranslator.CallTranslator
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.reference.ReferenceTranslator
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils.simpleReturnFunction
@@ -141,6 +142,8 @@ fun getReferenceToJsClass(classifierDescriptor: ClassifierDescriptor?, context:
else -> {
throw IllegalStateException("Can't get reference for $classifierDescriptor")
}
}.also {
it.primitiveKClass = ExpressionVisitor.getPrimitiveClass(context, classifierDescriptor)
}
}
@@ -1,4 +1,8 @@
// EXPECTED_REACHABLE_NODES: 1318
// FILE: lib.kt
// RECOMPILE
package foo
import kotlin.reflect.KClass
@@ -10,11 +14,17 @@ inline fun <reified T : Any> foo(b: Boolean = false): KClass<T> {
return T::class
}
// FILE: main.kt
package foo
fun box(): String {
check(A::class, foo<A>())
check(B::class, foo<B>())
check(O::class, foo<O>())
check(E::class, foo<E>())
check(Int::class, foo<Int>())
check(ByteArray::class, foo<ByteArray>())
return "OK"
}
@@ -0,0 +1,30 @@
// EXPECTED_REACHABLE_NODES: 1320
// IGNORE_BACKEND: JS
// FILE: lib.kt
// RECOMPILE
package foo
import kotlin.reflect.KClass
inline fun <reified T : Any> foo(b: Boolean = false): () -> KClass<T> {
if (b) {
val T = 1
}
return { T::class }
}
// FILE: main.kt
package foo
fun box(): String {
check(A::class, foo<A>()())
check(B::class, foo<B>()())
check(O::class, foo<O>()())
check(E::class, foo<E>()())
check(Int::class, foo<Int>()())
check(ByteArray::class, foo<ByteArray>()())
return "OK"
}
@@ -0,0 +1,51 @@
// EXPECTED_REACHABLE_NODES: 1321
// MODULE: lib
// FILE: lib.kt
inline fun <reified T: Any> klassLib() = T::class
// MODULE: main(lib)
// FILE: main.kt
import kotlin.reflect.KClass
inline fun <reified T: Any> klass() = T::class
fun box(): String {
check(js("Object"), "Any", klass<Any>())
check(js("String"), "String", klass<String>())
check(js("Boolean"), "Boolean", klass<Boolean>())
check(js("Error"), "Throwable", klass<Throwable>())
check(js("Array"), "Array", klass<Array<Any>>())
check(js("Function"), "Function0", klass<Function0<*>>())
check(js("Function"), "Function1", klass<Function1<*, *>>())
check(js("Number"), "Byte", klass<Byte>())
check(js("Number"), "Short", klass<Short>())
check(js("Number"), "Int", klass<Int>())
check(js("Number"), "Float", klass<Float>())
check(js("Number"), "Double", klass<Double>())
check(js("Number"), "Number", klass<Number>())
check(js("Array"), "BooleanArray", klass<BooleanArray>())
check(js("Uint16Array"), "CharArray", klass<CharArray>())
check(js("Int8Array"), "ByteArray", klass<ByteArray>())
check(js("Int16Array"), "ShortArray", klass<ShortArray>())
check(js("Int32Array"), "IntArray", klass<IntArray>())
check(js("Array"), "LongArray", klass<LongArray>())
check(js("Float32Array"), "FloatArray", klass<FloatArray>())
check(js("Float64Array"), "DoubleArray", klass<DoubleArray>())
// Check same instance
if (Int::class !== klass<Int>()) return "Same instance check failed"
// Check inlining from other module works
check(js("Int8Array"), "ByteArray", klassLib<ByteArray>())
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}")
}