JS/RTTI: fixed cast to generic type parameter with upper bound different than Any
This commit is contained in:
committed by
Alexey Andreev
parent
d42cbde74d
commit
cd60a8d207
@@ -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");
|
||||
|
||||
+7
-2
@@ -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"
|
||||
|
||||
+39
@@ -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"
|
||||
}
|
||||
+26
@@ -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"
|
||||
}
|
||||
Reference in New Issue
Block a user