JS IR: fix type checks for suspend function descendants (^KT-54382 fixed)

Consider `class A : suspend () -> Unit {}`. Type checks such as `is A`
are now performed via a regular `instanceof` check instead of the special
checks for suspend lambdas.
This commit is contained in:
Anton Bannykh
2022-10-12 11:52:34 +02:00
committed by Space Team
parent bc13173ea9
commit 9342356c38
7 changed files with 204 additions and 1 deletions
@@ -254,7 +254,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
toType is IrDynamicType -> argument
toType.isAny() -> generateIsObjectCheck(argument)
toType.isNothing() -> JsIrBuilder.buildComposite(context.irBuiltIns.booleanType, listOf(argument, litFalse))
toType.isSuspendFunctionTypeOrSubtype() -> generateSuspendFunctionCheck(argument, toType)
toType.isSuspendFunction() -> generateSuspendFunctionCheck(argument, toType)
isTypeOfCheckingType(toType) -> generateTypeOfCheck(argument, toType)
// toType.isChar() -> generateCheckForChar(argument)
toType.isNumber() -> generateNumberCheck(argument)
@@ -796,6 +796,12 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
runTest("js/js.translator/testData/box/coroutines/debugStatement.kt");
}
@Test
@TestMetadata("kt54382.kt")
public void testKt54382() throws Exception {
runTest("js/js.translator/testData/box/coroutines/kt54382.kt");
}
@Test
@TestMetadata("lambdaWithValueClass.kt")
public void testLambdaWithValueClass() throws Exception {
@@ -819,6 +825,18 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest {
public void testOnlyInlineSuspendFunction() throws Exception {
runTest("js/js.translator/testData/box/coroutines/onlyInlineSuspendFunction.kt");
}
@Test
@TestMetadata("suspendFunctionAsSupertypeIsCheck.kt")
public void testSuspendFunctionAsSupertypeIsCheck() throws Exception {
runTest("js/js.translator/testData/box/coroutines/suspendFunctionAsSupertypeIsCheck.kt");
}
@Test
@TestMetadata("suspendFunctionIsAs.kt")
public void testSuspendFunctionIsAs() throws Exception {
runTest("js/js.translator/testData/box/coroutines/suspendFunctionIsAs.kt");
}
}
@Nested
@@ -860,6 +860,12 @@ public class FirJsTestGenerated extends AbstractFirJsTest {
runTest("js/js.translator/testData/box/coroutines/debugStatement.kt");
}
@Test
@TestMetadata("kt54382.kt")
public void testKt54382() throws Exception {
runTest("js/js.translator/testData/box/coroutines/kt54382.kt");
}
@Test
@TestMetadata("lambdaWithValueClass.kt")
public void testLambdaWithValueClass() throws Exception {
@@ -883,6 +889,18 @@ public class FirJsTestGenerated extends AbstractFirJsTest {
public void testOnlyInlineSuspendFunction() throws Exception {
runTest("js/js.translator/testData/box/coroutines/onlyInlineSuspendFunction.kt");
}
@Test
@TestMetadata("suspendFunctionAsSupertypeIsCheck.kt")
public void testSuspendFunctionAsSupertypeIsCheck() throws Exception {
runTest("js/js.translator/testData/box/coroutines/suspendFunctionAsSupertypeIsCheck.kt");
}
@Test
@TestMetadata("suspendFunctionIsAs.kt")
public void testSuspendFunctionIsAs() throws Exception {
runTest("js/js.translator/testData/box/coroutines/suspendFunctionIsAs.kt");
}
}
@Nested
@@ -860,6 +860,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
runTest("js/js.translator/testData/box/coroutines/debugStatement.kt");
}
@Test
@TestMetadata("kt54382.kt")
public void testKt54382() throws Exception {
runTest("js/js.translator/testData/box/coroutines/kt54382.kt");
}
@Test
@TestMetadata("lambdaWithValueClass.kt")
public void testLambdaWithValueClass() throws Exception {
@@ -883,6 +889,18 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
public void testOnlyInlineSuspendFunction() throws Exception {
runTest("js/js.translator/testData/box/coroutines/onlyInlineSuspendFunction.kt");
}
@Test
@TestMetadata("suspendFunctionAsSupertypeIsCheck.kt")
public void testSuspendFunctionAsSupertypeIsCheck() throws Exception {
runTest("js/js.translator/testData/box/coroutines/suspendFunctionAsSupertypeIsCheck.kt");
}
@Test
@TestMetadata("suspendFunctionIsAs.kt")
public void testSuspendFunctionIsAs() throws Exception {
runTest("js/js.translator/testData/box/coroutines/suspendFunctionIsAs.kt");
}
}
@Nested
+29
View File
@@ -0,0 +1,29 @@
// WITH_STDLIB
// WITH_COROUTINES
typealias AsyncFun = suspend () -> Unit
val actions = arrayListOf<AsyncFun>()
private class SyncFunAdapter(private val target: () -> Unit) : AsyncFun {
override fun equals(other: Any?): Boolean {
return if (other is SyncFunAdapter) {
target == other.target
} else {
target == other
}
}
override fun hashCode() = target.hashCode()
override suspend fun invoke() {
target()
}
}
fun box(): String {
val x = SyncFunAdapter { }
actions.add(x)
if (!actions.remove(x)) return "FAIL 1"
return "OK"
}
@@ -0,0 +1,54 @@
// WITH_STDLIB
// !LANGUAGE: +SuspendFunctionAsSupertype
// IGNORE_BACKEND: JS
import kotlin.coroutines.*
class C: suspend () -> Unit {
override suspend fun invoke() {
}
}
interface I: suspend () -> Unit {}
fun interface FI: suspend () -> Unit {}
@Suppress("INCOMPATIBLE_TYPES")
fun box(): String {
val c = C()
if (c !is SuspendFunction0<*>) return "FAIL 1"
if (c is SuspendFunction1<*, *>) return "FAIL 3"
val i = object : I {
override suspend fun invoke() {
}
}
if (i !is SuspendFunction0<Unit>) return "FAIL 4"
if (i is SuspendFunction1<*, *>) return "FAIL 6"
val fi = object : FI {
override suspend fun invoke() {
}
}
if (fi !is SuspendFunction0<Unit>) return "FAIL 7"
if (fi is SuspendFunction1<*, *>) return "FAIL 9"
val o = object : suspend () -> Unit {
override suspend fun invoke() {
}
}
if (o !is SuspendFunction0<Unit>) return "FAIL 10"
if (o is SuspendFunction1<*, *>) return "FAIL 12"
if (c !is C) return "FAIL 13"
if (i !is I) return "FAIL 14"
if (fi !is FI) return "FAIL 15"
if (c !is C) return "FAIL 16"
val a: Any = c
if (a !is C) return "FAIL 17"
if (i !is I) return "FAIL 18"
if (fi !is FI) return "FAIL 19"
return "OK"
}
@@ -0,0 +1,66 @@
// WITH_STDLIB
// WITH_COROUTINES
// IGNORE_BACKEND: JS
import helpers.*
import kotlin.coroutines.*
fun check(condition: Boolean, msg: () -> Unit) {
if (!condition) {
throw AssertionError(msg())
}
}
fun fn1(x: Any) {}
suspend fun suspendFn0() {}
val lambda1 = { x: Any -> } as (Any) -> Unit
val suspendLambda0: suspend () -> Unit = {}
fun Any.extFun(a: Any) {}
suspend fun Any.suspendExtFun() {}
class A {
fun foo(a: Any) {}
suspend fun suspendFoo() {}
}
inline fun <reified T : suspend () -> Unit> checkReified(noinline x: (Any?) -> Unit) {
if(x is T) throw IllegalStateException("x is T")
}
fun box(): String {
val f1 = ::fn1 as Any
val sf0 = ::suspendFn0 as Any
val ef = Any::extFun as Any
val sef = Any::suspendExtFun as Any
val afoo = A::foo
val safoo = A::suspendFoo
fun local1(x: Any) {}
suspend fun suspendLocal0() {}
val localFun1 = ::local1 as Any
val suspendLocalFun0 = ::suspendLocal0 as Any
check(f1 !is SuspendFunction0<*>) { "Failed: f1 !is SuspendFunction0<*>" }
check(sf0 is SuspendFunction0<*>) { "Failed: f1 is SuspendFunction0<*>" }
check(lambda1 !is SuspendFunction0<*>) { "Failed: lambda1 !is SuspendFunction0<*>" }
check(suspendLambda0 is SuspendFunction0<*>) { "Failed: suspendLambda0 is SuspendFunction0<*>" }
check(localFun1 !is SuspendFunction0<*>) { "Failed: localFun1 !is SuspendFunction0<*, *>" }
check(suspendLocalFun0 is SuspendFunction0<*>) { "Failed: suspendLocalFun0 is SuspendFunction0<*>" }
check(ef !is SuspendFunction1<*, *>) { "Failed: ef !is SuspendFunction1<*, *>" }
check(sef is SuspendFunction1<*, *>) { "Failed: sef is SuspendFunction1<*, *>" }
check(afoo !is SuspendFunction1<*, *>) { "afoo !is SuspendFunction1<*, *>" }
check(safoo is SuspendFunction1<*, *>) { "asfoo is SuspendFunction1<*, *>" }
checkReified<suspend () -> Unit> {}
return "OK"
}