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);
|
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")
|
@TestMetadata("castToNotNull.kt")
|
||||||
public void testCastToNotNull() throws Exception {
|
public void testCastToNotNull() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToNotNull.kt");
|
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/castToNotNull.kt");
|
||||||
@@ -77,6 +83,12 @@ public class CastTestGenerated extends AbstractCastTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("safeCastToNotNull.kt")
|
||||||
public void testSafeCastToNotNull() throws Exception {
|
public void testSafeCastToNotNull() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/expression/cast/cases/safeCastToNotNull.kt");
|
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.resolve.DescriptorUtils;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
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.FunctionTypesKt.isFunctionTypeOrSubtype;
|
||||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isAnyOrNullableAny;
|
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isAnyOrNullableAny;
|
||||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isArray;
|
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) {
|
public JsExpression translateIsCheck(@NotNull JsExpression subject, @NotNull KtTypeReference typeReference) {
|
||||||
KotlinType type = BindingUtils.getTypeByReference(bindingContext(), typeReference);
|
KotlinType type = BindingUtils.getTypeByReference(bindingContext(), typeReference);
|
||||||
JsExpression checkFunReference = doGetIsTypeCheckCallable(type);
|
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);
|
checkFunReference = namer().orNull(checkFunReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +147,7 @@ public final class PatternTranslator extends AbstractTranslator {
|
|||||||
return getIsTypeCheckCallableForReifiedType(typeParameterDescriptor);
|
return getIsTypeCheckCallableForReifiedType(typeParameterDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return namer().isAny();
|
return doGetIsTypeCheckCallable(typeParameterDescriptor.getUpperBoundsAsType());
|
||||||
}
|
}
|
||||||
|
|
||||||
JsNameRef typeName = getClassNameReference(type);
|
JsNameRef typeName = getClassNameReference(type);
|
||||||
|
|||||||
@@ -4,6 +4,15 @@ package kotlin
|
|||||||
// CHECK_NOT_REFERENCED: Kotlin.isTypeOf
|
// CHECK_NOT_REFERENCED: Kotlin.isTypeOf
|
||||||
// CHECK_NOT_REFERENCED: Kotlin.orNull
|
// 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) {
|
fun failsClassCast(message: String, fn: ()->Unit) {
|
||||||
try {
|
try {
|
||||||
fn()
|
fn()
|
||||||
|
|||||||
@@ -37,13 +37,13 @@ fun <T : Any> castsNullableToNotNullT(a: Any?) {
|
|||||||
fun box(): String {
|
fun box(): String {
|
||||||
val a = A("OK")
|
val a = A("OK")
|
||||||
|
|
||||||
castsNotNullToNullableT<A>(a)
|
success("castsNotNullToNullableT<A>(a)") { castsNotNullToNullableT<A>(a) }
|
||||||
castsNullableToNullableT<A>(a)
|
success("castsNullableToNullableT<A>(a)") { castsNullableToNullableT<A>(a) }
|
||||||
castsNullableToNullableT<A>(null)
|
success("castsNullableToNullableT<A>(null)") { castsNullableToNullableT<A>(null) }
|
||||||
castsNotNullToNotNullT<A>(a)
|
success("castsNotNullToNotNullT<A>(a)") { castsNotNullToNotNullT<A>(a) }
|
||||||
castsNullableToNotNullT<A>(a)
|
success("castsNullableToNotNullT<A>(a)") { castsNullableToNotNullT<A>(a) }
|
||||||
castsNullableToNotNullT<A>(null)
|
success("castsNullableToNotNullT<A>(null)") { castsNullableToNotNullT<A>(null) }
|
||||||
castNullableToNotNullT<A>(a)
|
success("castNullableToNotNullT<A>(a)") { castNullableToNotNullT<A>(a) }
|
||||||
failsClassCast("castNullableToNotNullT<A>(null)") { castNullableToNotNullT<A>(null) }
|
failsClassCast("castNullableToNotNullT<A>(null)") { castNullableToNotNullT<A>(null) }
|
||||||
|
|
||||||
return "OK"
|
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