JS/RTTI: fixed cast to generic type parameter with upper bound different than Any

This commit is contained in:
Alexey Tsvetkov
2015-06-24 17:15:23 +03:00
committed by Alexey Andreev
parent d42cbde74d
commit cd60a8d207
6 changed files with 100 additions and 9 deletions
@@ -53,6 +53,12 @@ public class CastTestGenerated extends AbstractCastTest {
doTest(fileName);
}
@TestMetadata("castToGenericTypeWithUpperBound.kt")
public void testCastToGenericTypeWithUpperBound() throws Exception {
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToGenericTypeWithUpperBound.kt");
doTest(fileName);
}
@TestMetadata("castToNotNull.kt")
public void testCastToNotNull() throws Exception {
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToNotNull.kt");
@@ -77,6 +83,12 @@ public class CastTestGenerated extends AbstractCastTest {
doTest(fileName);
}
@TestMetadata("safeCastToGenericTypeWithUpperBound.kt")
public void testSafeCastToGenericTypeWithUpperBound() throws Exception {
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/safeCastToGenericTypeWithUpperBound.kt");
doTest(fileName);
}
@TestMetadata("safeCastToNotNull.kt")
public void testSafeCastToNotNull() throws Exception {
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/safeCastToNotNull.kt");
@@ -42,6 +42,8 @@ import org.jetbrains.kotlin.psi.KtTypeReference;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.types.KotlinType;
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.*;
import static org.jetbrains.kotlin.js.descriptorUtils.DescriptorUtilsPackage.getNameIfStandardType;
import static org.jetbrains.kotlin.builtins.FunctionTypesKt.isFunctionTypeOrSubtype;
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isAnyOrNullableAny;
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isArray;
@@ -106,8 +108,11 @@ public final class PatternTranslator extends AbstractTranslator {
public JsExpression translateIsCheck(@NotNull JsExpression subject, @NotNull KtTypeReference typeReference) {
KotlinType type = BindingUtils.getTypeByReference(bindingContext(), typeReference);
JsExpression checkFunReference = doGetIsTypeCheckCallable(type);
boolean isReifiedType = isReifiedTypeParameter(type);
if (isReifiedTypeParameter(type) && findChildByType(typeReference, KtNodeTypes.NULLABLE_TYPE) != null) {
if (!isReifiedType && isNullableType(type) ||
isReifiedType && findChildByType(typeReference, KtNodeTypes.NULLABLE_TYPE) != null
) {
checkFunReference = namer().orNull(checkFunReference);
}
@@ -142,7 +147,7 @@ public final class PatternTranslator extends AbstractTranslator {
return getIsTypeCheckCallableForReifiedType(typeParameterDescriptor);
}
return namer().isAny();
return doGetIsTypeCheckCallable(typeParameterDescriptor.getUpperBoundsAsType());
}
JsNameRef typeName = getClassNameReference(type);
@@ -4,6 +4,15 @@ package kotlin
// CHECK_NOT_REFERENCED: Kotlin.isTypeOf
// CHECK_NOT_REFERENCED: Kotlin.orNull
fun success(message: String, fn: ()->Unit) {
try {
fn()
}
catch (e: Exception) {
throw Exception("Exception was thrown: message=$message, exception=$e")
}
}
fun failsClassCast(message: String, fn: ()->Unit) {
try {
fn()
@@ -37,13 +37,13 @@ fun <T : Any> castsNullableToNotNullT(a: Any?) {
fun box(): String {
val a = A("OK")
castsNotNullToNullableT<A>(a)
castsNullableToNullableT<A>(a)
castsNullableToNullableT<A>(null)
castsNotNullToNotNullT<A>(a)
castsNullableToNotNullT<A>(a)
castsNullableToNotNullT<A>(null)
castNullableToNotNullT<A>(a)
success("castsNotNullToNullableT<A>(a)") { castsNotNullToNullableT<A>(a) }
success("castsNullableToNullableT<A>(a)") { castsNullableToNullableT<A>(a) }
success("castsNullableToNullableT<A>(null)") { castsNullableToNullableT<A>(null) }
success("castsNotNullToNotNullT<A>(a)") { castsNotNullToNotNullT<A>(a) }
success("castsNullableToNotNullT<A>(a)") { castsNullableToNotNullT<A>(a) }
success("castsNullableToNotNullT<A>(null)") { castsNullableToNotNullT<A>(null) }
success("castNullableToNotNullT<A>(a)") { castNullableToNotNullT<A>(a) }
failsClassCast("castNullableToNotNullT<A>(null)") { castNullableToNotNullT<A>(null) }
return "OK"
@@ -0,0 +1,39 @@
package foo
open class A
class B : A()
class C
fun notNullToNotNullT<T : A>(a: Any): T = a as T
fun nullableToNotNullT<T : A>(a: Any?): T = a as T
fun notNullToNullableT<T : A>(a: Any): T? = a as T?
fun nullableToNullableT<T : A>(a: Any?): T? = a as T?
fun box(): String {
val a = A()
val b = B()
val c = C()
success("notNullToNotNullT<A>(a)") { assertEquals(a, notNullToNotNullT<A>(a)) }
success("notNullToNotNullT<A>(b)") { assertEquals(b, notNullToNotNullT<A>(b)) }
failsClassCast("notNullToNotNullT<A>(c)") { notNullToNotNullT<A>(c) }
success("nullableToNotNullT<A>(a)") {assertEquals(a, nullableToNotNullT<A>(a)) }
success("nullableToNotNullT<A>(b)") {assertEquals(b, nullableToNotNullT<A>(b)) }
failsClassCast("nullableToNotNullT<A>(c)") { nullableToNotNullT<A>(c) }
failsClassCast("nullableToNotNullT<A>(null)") { nullableToNotNullT<A>(null) }
success("notNullToNullableT<A>(a)") { assertEquals(a, notNullToNullableT<A>(a))}
success("notNullToNullableT<A>(b)") { assertEquals(b, notNullToNullableT<A>(b))}
failsClassCast("notNullToNullableT<A>(c)") { notNullToNullableT<A>(c) }
success("nullableToNullableT<A>(a)") { assertEquals(a, nullableToNullableT<A>(a)) }
success("nullableToNullableT<A>(b)") { assertEquals(b, nullableToNullableT<A>(b)) }
success("nullableToNullableT<A>(null)") { assertEquals(null, nullableToNullableT<A>(null)) }
failsClassCast("nullableToNullableT<A>(c)") { nullableToNullableT<A>(c) }
return "OK"
}
@@ -0,0 +1,26 @@
package foo
open class A
class B : A()
class C
fun notNullToNullableT<T : A>(a: Any): T? = a as? T?
fun nullableToNullableT<T : A>(a: Any?): T? = a as? T?
fun box(): String {
val a = A()
val b = B()
val c = C()
success("notNullToNullableT<A>(a)") { assertEquals(a, notNullToNullableT<A>(a)) }
success("notNullToNullableT<A>(b)") { assertEquals(b, notNullToNullableT<A>(b)) }
success("notNullToNullableT<A>(c)") { assertEquals(null, notNullToNullableT<A>(c)) }
success("nullableToNullableT<A>(a)") { assertEquals(a, nullableToNullableT<A>(a)) }
success("nullableToNullableT<A>(b)") { assertEquals(b, nullableToNullableT<A>(b)) }
success("nullableToNullableT<A>(null)") { assertEquals(null, nullableToNullableT<A>(null)) }
success("nullableToNullableT<A>(c)") { assertEquals(null, nullableToNullableT<A>(c)) }
return "OK"
}