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:
committed by
Space Team
parent
bc13173ea9
commit
9342356c38
+1
-1
@@ -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
|
||||
|
||||
+18
@@ -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
|
||||
|
||||
+18
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
+54
@@ -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"
|
||||
}
|
||||
Reference in New Issue
Block a user