From 4a7703ed665b52a77b1518e28802fe1b22a1889e Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Fri, 10 Aug 2018 20:22:06 +0300 Subject: [PATCH] Implement correct is check for SuspendFunction Let callable references implement SuspendFunction Do not generate CHECKCAST SuspendFunction when LV is 1.2 #KT-25825: Fixed --- .../kotlin/codegen/ExpressionCodegen.java | 2 +- .../kotlin/codegen/JvmRuntimeTypes.kt | 9 ++- .../jetbrains/kotlin/codegen/codegenUtil.kt | 16 +++-- .../codegen/intrinsics/TypeIntrinsics.kt | 60 ++++++++++++------ .../kotlin/resolve/jvm/AsmTypes.java | 17 ++---- .../featureIntersection/suspendFunction12.kt | 19 ++++++ .../suspendFunctionIsAs.kt | 61 +++++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 10 +++ .../LightAnalysisModeTestGenerated.java | 10 +++ .../ir/IrBlackBoxCodegenTestGenerated.java | 10 +++ .../IrJsCodegenBoxTestGenerated.java | 10 +++ .../semantics/JsCodegenBoxTestGenerated.java | 10 +++ .../jvm/internal/ContinuationImpl.kt | 8 ++- 13 files changed, 202 insertions(+), 40 deletions(-) create mode 100644 compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunction12.kt create mode 100644 compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionIsAs.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 48ba2268e63..04442ce6343 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -4658,7 +4658,7 @@ The "returned" value of try expression with no finally is either the last expres return null; } - CodegenUtilKt.generateIsCheck(v, rhsKotlinType, type); + CodegenUtilKt.generateIsCheck(v, rhsKotlinType, type, state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines)); return null; }); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.kt index 9d51af05667..ad84a225461 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/JvmRuntimeTypes.kt @@ -57,6 +57,12 @@ class JvmRuntimeTypes(module: ModuleDescriptor, private val languageVersionSetti createCoroutineSuperClass("RestrictedSuspendLambda") } + private val suspendFunctionInterface by lazy { + if (languageVersionSettings.isReleaseCoroutines()) + createClass(kotlinCoroutinesJvmInternalPackage, "SuspendFunction", ClassKind.INTERFACE) + else null + } + private fun createCoroutineSuperClass(className: String): ClassDescriptor { return if (languageVersionSettings.isReleaseCoroutines()) createClass(kotlinCoroutinesJvmInternalPackage, className) @@ -145,7 +151,8 @@ class JvmRuntimeTypes(module: ModuleDescriptor, private val languageVersionSetti referencedFunction.isSuspend ) - return listOf(functionReference.defaultType, functionType) + val suspendFunctionType = if (referencedFunction.isSuspend) suspendFunctionInterface?.defaultType else null + return listOfNotNull(functionReference.defaultType, functionType, suspendFunctionType) } fun getSupertypeForPropertyReference(descriptor: VariableDescriptorWithAccessors, isMutable: Boolean, isBound: Boolean): KotlinType { diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt index faa645e4eaf..c91c7caddd7 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt @@ -1,5 +1,5 @@ /* - * Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * that can be found in the license/LICENSE.txt file. */ @@ -59,10 +59,12 @@ import java.io.PrintWriter import java.io.StringWriter import java.util.* +@JvmOverloads fun generateIsCheck( v: InstructionAdapter, kotlinType: KotlinType, - asmType: Type + asmType: Type, + isReleaseCoroutines: Boolean = false ) { if (TypeUtils.isNullableType(kotlinType)) { val nope = Label() @@ -73,7 +75,7 @@ fun generateIsCheck( ifnull(nope) - TypeIntrinsics.instanceOf(this, kotlinType, asmType) + TypeIntrinsics.instanceOf(this, kotlinType, asmType, isReleaseCoroutines) goTo(end) @@ -84,15 +86,17 @@ fun generateIsCheck( mark(end) } } else { - TypeIntrinsics.instanceOf(v, kotlinType, asmType) + TypeIntrinsics.instanceOf(v, kotlinType, asmType, isReleaseCoroutines) } } +@JvmOverloads fun generateAsCast( v: InstructionAdapter, kotlinType: KotlinType, asmType: Type, - isSafe: Boolean + isSafe: Boolean, + isReleaseCoroutines: Boolean = false ) { if (!isSafe) { if (!TypeUtils.isNullableType(kotlinType)) { @@ -101,7 +105,7 @@ fun generateAsCast( } else { with(v) { dup() - TypeIntrinsics.instanceOf(v, kotlinType, asmType) + TypeIntrinsics.instanceOf(v, kotlinType, asmType, isReleaseCoroutines) val ok = Label() ifne(ok) pop() diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/TypeIntrinsics.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/TypeIntrinsics.kt index 2947759895b..305eed42e60 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/TypeIntrinsics.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/TypeIntrinsics.kt @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.codegen.intrinsics @@ -19,8 +8,10 @@ package org.jetbrains.kotlin.codegen.intrinsics import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -28,7 +19,8 @@ import org.jetbrains.org.objectweb.asm.tree.* import kotlin.text.Regex object TypeIntrinsics { - @JvmStatic fun instanceOf(v: InstructionAdapter, jetType: KotlinType, boxedAsmType: Type) { + @JvmStatic + fun instanceOf(v: InstructionAdapter, jetType: KotlinType, boxedAsmType: Type, isReleaseCoroutines: Boolean) { val functionTypeArity = getFunctionTypeArity(jetType) if (functionTypeArity >= 0) { v.iconst(functionTypeArity) @@ -36,6 +28,30 @@ object TypeIntrinsics { return } + if (isReleaseCoroutines) { + val suspendFunctionTypeArity = getSuspendFunctionTypeArity(jetType) + if (suspendFunctionTypeArity >= 0) { + val notSuspendLambda = Label() + val end = Label() + + with(v) { + dup() + instanceOf(AsmTypes.SUSPEND_FUNCTION_TYPE) + ifeq(notSuspendLambda) + iconst(suspendFunctionTypeArity + 1) + typeIntrinsic(IS_FUNCTON_OF_ARITY_METHOD_NAME, IS_FUNCTON_OF_ARITY_DESCRIPTOR) + goTo(end) + + mark(notSuspendLambda) + pop() + iconst(0) + + mark(end) + } + return + } + } + val isMutableCollectionMethodName = getIsMutableCollectionMethodName(jetType) if (isMutableCollectionMethodName != null) { v.typeIntrinsic(isMutableCollectionMethodName, IS_MUTABLE_COLLECTION_METHOD_DESCRIPTOR) @@ -148,16 +164,26 @@ object TypeIntrinsics { } private val KOTLIN_FUNCTION_INTERFACE_REGEX = Regex("^kotlin\\.Function([0-9]+)$") + // TODO: move to correct package + private val KOTLIN_SUSPEND_FUNCTION_INTERFACE_REGEX = Regex("^kotlin\\.SuspendFunction([0-9]+)$") /** * @return function type arity (non-negative), or -1 if the given type is not a function type */ - private fun getFunctionTypeArity(jetType: KotlinType): Int { - val classFqName = getClassFqName(jetType) ?: return -1 - val match = KOTLIN_FUNCTION_INTERFACE_REGEX.find(classFqName.asString()) ?: return -1 + private fun getFunctionTypeArity(kotlinType: KotlinType): Int = getFunctionTypeArityByRegex(kotlinType, KOTLIN_FUNCTION_INTERFACE_REGEX) + + private fun getFunctionTypeArityByRegex(kotlinType: KotlinType, regex: Regex): Int { + val classFqName = getClassFqName(kotlinType) ?: return -1 + val match = regex.find(classFqName.asString()) ?: return -1 return Integer.valueOf(match.groups[1]!!.value) } + /** + * @return function type arity (non-negative, counting continuation), or -1 if the given type is not a function type + */ + private fun getSuspendFunctionTypeArity(kotlinType: KotlinType): Int = + getFunctionTypeArityByRegex(kotlinType, KOTLIN_SUSPEND_FUNCTION_INTERFACE_REGEX) + private fun typeIntrinsicNode(methodName: String, methodDescriptor: String): MethodInsnNode = MethodInsnNode(Opcodes.INVOKESTATIC, INTRINSICS_CLASS, methodName, methodDescriptor, false) diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java index e3f17b96a82..97be4621462 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/AsmTypes.java @@ -1,17 +1,6 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. */ package org.jetbrains.kotlin.resolve.jvm; @@ -74,6 +63,8 @@ public class AsmTypes { public static final Type K_MUTABLE_PROPERTY1_TYPE = reflect("KMutableProperty1"); public static final Type K_MUTABLE_PROPERTY2_TYPE = reflect("KMutableProperty2"); + public static final Type SUSPEND_FUNCTION_TYPE = Type.getObjectType("kotlin/coroutines/jvm/internal/SuspendFunction"); + public static final String REFLECTION = "kotlin/jvm/internal/Reflection"; public static final String REF_TYPE_PREFIX = "kotlin/jvm/internal/Ref$"; diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunction12.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunction12.kt new file mode 100644 index 00000000000..917ecf9b4f0 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunction12.kt @@ -0,0 +1,19 @@ +// IGNORE_BACKEND: JS_IR, JS +// IGNORE_BACKEND: JVM_IR +// WITH_RUNTIME +// WITH_COROUTINES +// LANGUAGE_VERSION: 1.2 + +import helpers.* +import kotlin.coroutines.* + +val lambda1 = { x: Any -> } as (Any) -> Unit +val suspendLambda0: suspend () -> Unit = {} + +fun box(): String { + assert(lambda1 is SuspendFunction0<*>) { "Failed: lambda1 !is SuspendFunction0<*>" } + assert(suspendLambda0 is Function1<*, *>) { "Failed: suspendLambda0 is Function1<*, *>" } + assert(suspendLambda0 is SuspendFunction0<*>) { "Failed: suspendLambda0 is SuspendFunction0<*>" } + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionIsAs.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionIsAs.kt new file mode 100644 index 00000000000..2e43794aa9c --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionIsAs.kt @@ -0,0 +1,61 @@ +// IGNORE_BACKEND: JS_IR, JS +// IGNORE_BACKEND: JVM_IR +// WITH_RUNTIME +// WITH_COROUTINES +// LANGUAGE_VERSION: 1.3 + +import helpers.* +import kotlin.coroutines.* + +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() {} +} + +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 + + assert(f1 !is SuspendFunction0<*>) { "Failed: f1 !is SuspendFunction0<*>" } + assert(sf0 is SuspendFunction0<*>) { "Failed: f1 is SuspendFunction0<*>" } + assert(sf0 is Function1<*, *>) { "Failed: suspendF0 is Function1<*, *>" } + + assert(lambda1 !is SuspendFunction0<*>) { "Failed: lambda1 !is SuspendFunction0<*>" } + assert(suspendLambda0 is Function1<*, *>) { "Failed: suspendLambda0 is Function1<*, *>" } + assert(suspendLambda0 is SuspendFunction0<*>) { "Failed: suspendLambda0 is SuspendFunction0<*>" } + + assert(localFun1 !is SuspendFunction0<*>) { "Failed: localFun1 !is SuspendFunction0<*, *>" } + assert(suspendLocalFun0 is Function1<*, *>) { "Failed: suspendLocalFun0 is Function1<*, *>" } + assert(suspendLocalFun0 is SuspendFunction0<*>) { "Failed: suspendLocalFun0 is SuspendFunction0<*>" } + + assert(ef !is SuspendFunction1<*, *>) { "Failed: ef !is SuspendFunction1<*, *>" } + assert(sef is SuspendFunction1<*, *>) { "Failed: sef is SuspendFunction1<*, *>" } + assert(sef is Function2<*, *, *>) { "Failed: sef is Function2<*, *, *>" } + + assert(afoo !is SuspendFunction1<*, *>) { "afoo !is SuspendFunction1<*, *>" } + assert(safoo is Function2<*, *, *>) { "safoo is Function2<*, *, *>" } + assert(safoo is SuspendFunction1<*, *>) { "asfoo is SuspendFunction1<*, *>" } + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 032d101466f..9241ed1dfcd 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -6505,6 +6505,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/suspendDestructuringInLambdas.kt", "kotlin.coroutines"); } + @TestMetadata("suspendFunction12.kt") + public void testSuspendFunction12() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunction12.kt"); + } + + @TestMetadata("suspendFunctionIsAs.kt") + public void testSuspendFunctionIsAs() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionIsAs.kt"); + } + @TestMetadata("suspendOperatorPlusAssign.kt") public void testSuspendOperatorPlusAssign_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusAssign.kt", "kotlin.coroutines.experimental"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index e7a078c52a7..8bdd22788f4 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -6505,6 +6505,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/suspendDestructuringInLambdas.kt", "kotlin.coroutines"); } + @TestMetadata("suspendFunction12.kt") + public void testSuspendFunction12() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunction12.kt"); + } + + @TestMetadata("suspendFunctionIsAs.kt") + public void testSuspendFunctionIsAs() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionIsAs.kt"); + } + @TestMetadata("suspendOperatorPlusAssign.kt") public void testSuspendOperatorPlusAssign_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusAssign.kt", "kotlin.coroutines.experimental"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 9d19d2a329e..443cf6d09d3 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -6505,6 +6505,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/suspendDestructuringInLambdas.kt", "kotlin.coroutines"); } + @TestMetadata("suspendFunction12.kt") + public void testSuspendFunction12() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunction12.kt"); + } + + @TestMetadata("suspendFunctionIsAs.kt") + public void testSuspendFunctionIsAs() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionIsAs.kt"); + } + @TestMetadata("suspendOperatorPlusAssign.kt") public void testSuspendOperatorPlusAssign_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusAssign.kt", "kotlin.coroutines.experimental"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java index ce5a8a897df..8aa376f5423 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrJsCodegenBoxTestGenerated.java @@ -5665,6 +5665,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/suspendDestructuringInLambdas.kt", "kotlin.coroutines.experimental"); } + @TestMetadata("suspendFunction12.kt") + public void testSuspendFunction12() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunction12.kt"); + } + + @TestMetadata("suspendFunctionIsAs.kt") + public void testSuspendFunctionIsAs() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionIsAs.kt"); + } + @TestMetadata("suspendOperatorPlusAssign.kt") public void testSuspendOperatorPlusAssign_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusAssign.kt", "kotlin.coroutines.experimental"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 94eeab2e04b..939316f4e32 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -6220,6 +6220,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/suspendDestructuringInLambdas.kt", "kotlin.coroutines"); } + @TestMetadata("suspendFunction12.kt") + public void testSuspendFunction12() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunction12.kt"); + } + + @TestMetadata("suspendFunctionIsAs.kt") + public void testSuspendFunctionIsAs() throws Exception { + runTest("compiler/testData/codegen/box/coroutines/featureIntersection/suspendFunctionIsAs.kt"); + } + @TestMetadata("suspendOperatorPlusAssign.kt") public void testSuspendOperatorPlusAssign_1_2() throws Exception { runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/featureIntersection/suspendOperatorPlusAssign.kt", "kotlin.coroutines.experimental"); diff --git a/libraries/stdlib/coroutines/jvm/src/kotlin/coroutines/jvm/internal/ContinuationImpl.kt b/libraries/stdlib/coroutines/jvm/src/kotlin/coroutines/jvm/internal/ContinuationImpl.kt index ea01c7defad..75884242e39 100644 --- a/libraries/stdlib/coroutines/jvm/src/kotlin/coroutines/jvm/internal/ContinuationImpl.kt +++ b/libraries/stdlib/coroutines/jvm/src/kotlin/coroutines/jvm/internal/ContinuationImpl.kt @@ -125,12 +125,16 @@ internal object CompletedContinuation : Continuation { override fun toString(): String = "This continuation is already complete" } +@SinceKotlin("1.3") +// To distinguish suspend function types from ordinary function types all suspend function type shall implement this interface +internal interface SuspendFunction + @SinceKotlin("1.3") // Restricted suspension lambdas inherit from this class internal abstract class RestrictedSuspendLambda( private val arity: Int, completion: Continuation? -) : RestrictedContinuationImpl(completion), FunctionBase { +) : RestrictedContinuationImpl(completion), FunctionBase, SuspendFunction { constructor(arity: Int) : this(arity, null) public override fun getArity(): Int = arity @@ -147,7 +151,7 @@ internal abstract class RestrictedSuspendLambda( internal abstract class SuspendLambda( private val arity: Int, completion: Continuation? -) : ContinuationImpl(completion), FunctionBase { +) : ContinuationImpl(completion), FunctionBase, SuspendFunction { constructor(arity: Int) : this(arity, null) public override fun getArity(): Int = arity