diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 7f365833f75..230ae1a8e0a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -23,9 +23,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.codegen.binding.CalculatedClosure; import org.jetbrains.kotlin.codegen.binding.CodegenBinding; import org.jetbrains.kotlin.codegen.context.*; -import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenForLambda; -import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt; -import org.jetbrains.kotlin.codegen.coroutines.ResolvedCallWithRealDescriptor; +import org.jetbrains.kotlin.codegen.coroutines.*; import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension; import org.jetbrains.kotlin.codegen.inline.*; import org.jetbrains.kotlin.codegen.intrinsics.*; @@ -1238,7 +1236,7 @@ public class ExpressionCodegen extends KtVisitor impleme @Nullable public StackValue genCoroutineInstanceForSuspendLambda(@NotNull FunctionDescriptor suspendFunction) { - if (!(suspendFunction instanceof AnonymousFunctionDescriptor)) return null; + if (!CoroutineCodegenUtilKt.isSuspendLambdaOrLocalFunction(suspendFunction)) return null; ClassDescriptor suspendLambdaClassDescriptor = bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, suspendFunction); assert suspendLambdaClassDescriptor != null : "Coroutine class descriptor should not be null"; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java index 6717be04fa2..5b090c5bcec 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/StackValue.java @@ -15,6 +15,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.PrimitiveType; +import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt; import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt; import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; @@ -704,6 +705,18 @@ public abstract class StackValue { return codegen.generateReceiverValue(receiverValue, false); } else if (isLocalFunCall(callableMethod) && !isExtension) { + if (descriptor instanceof SimpleFunctionDescriptor) { + SimpleFunctionDescriptor initial = + CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction((SimpleFunctionDescriptor) descriptor); + if (initial != null && initial.isSuspend()) { + StackValue value = codegen.findLocalOrCapturedValue(initial.getOriginal()); + assert value != null : "Local suspend fun should be found in locals or in captured params: " + + descriptor + + " initial local suspend fun: " + + initial; + return value; + } + } StackValue value = codegen.findLocalOrCapturedValue(descriptor.getOriginal()); assert value != null : "Local fun should be found in locals or in captured params: " + descriptor; return value; diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java index 2f34bf2d878..3e169aecf49 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java @@ -506,7 +506,8 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { String nameForClassOrPackageMember = getNameForClassOrPackageMember(functionDescriptor); - if (functionDescriptor instanceof SimpleFunctionDescriptor && functionDescriptor.isSuspend()) { + if (functionDescriptor instanceof SimpleFunctionDescriptor && functionDescriptor.isSuspend() && + !functionDescriptor.getVisibility().equals(Visibilities.LOCAL)) { SimpleFunctionDescriptor jvmSuspendFunctionView = CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView( (SimpleFunctionDescriptor) functionDescriptor @@ -563,11 +564,29 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { else { String name = inventAnonymousClassName(); ClassDescriptor classDescriptor = recordClassForFunction(function, functionDescriptor, name, null); - recordClosure(classDescriptor, name); + MutableClosure closure = recordClosure(classDescriptor, name); classStack.push(classDescriptor); - functionsStack.push(functionDescriptor); nameStack.push(name); + + if (functionDescriptor instanceof SimpleFunctionDescriptor && functionDescriptor.isSuspend()) { + SimpleFunctionDescriptor jvmSuspendFunctionView = + CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView( + (SimpleFunctionDescriptor) functionDescriptor, + /*bindingContext*/ null, + /*dropSuspend*/ true + ); + + bindingTrace.record( + CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, + functionDescriptor, + jvmSuspendFunctionView + ); + closure.setSuspend(true); + closure.setSuspendLambda(); + } + + functionsStack.push(functionDescriptor); super.visitNamedFunction(function); functionsStack.pop(); nameStack.pop(); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt index a0854b9e6e5..c42887df808 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/CoroutineCodegen.kt @@ -20,10 +20,7 @@ import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.KtDeclarationWithBody -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.psi.KtFunction -import org.jetbrains.kotlin.psi.KtFunctionLiteral +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.module @@ -330,7 +327,7 @@ class CoroutineCodegenForLambda private constructor( declaration: KtElement, classBuilder: ClassBuilder ): ClosureCodegen? { - if (declaration !is KtFunctionLiteral || !originalSuspendLambdaDescriptor.isSuspendLambda) return null + if (!originalSuspendLambdaDescriptor.isSuspendLambdaOrLocalFunction()) return null return CoroutineCodegenForLambda( expressionCodegen, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt index 9a431c3c84a..4c61ab5d3d8 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/coroutines/coroutineCodegenUtil.kt @@ -26,8 +26,10 @@ import org.jetbrains.kotlin.codegen.inline.addFakeContinuationMarker import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.codegen.topLevelClassAsmType import org.jetbrains.kotlin.codegen.topLevelClassInternalName +import org.jetbrains.kotlin.coroutines.isSuspendLambda import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.Name @@ -182,7 +184,7 @@ fun ResolvedCall<*>.isSuspendNoInlineCall(codegen: ExpressionCodegen): Boolean { ?.let { it.isCrossinline || (!it.isNoinline && codegen.context.functionDescriptor.isInline) } == true val functionDescriptor = resultingDescriptor as? FunctionDescriptor ?: return false - if (!functionDescriptor.isSuspend) return false + if (!functionDescriptor.unwrapInitialDescriptorForSuspendFunction().isSuspend) return false if (functionDescriptor.isBuiltInSuspendCoroutineOrReturnInJvm() || functionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm()) return true return !(functionDescriptor.isInline || isInlineLambda) } @@ -196,7 +198,11 @@ fun CallableDescriptor.isSuspendFunctionNotSuspensionView(): Boolean { // and return type Any? // This function returns a function descriptor reflecting how the suspend function looks from point of view of JVM @JvmOverloads -fun getOrCreateJvmSuspendFunctionView(function: D, bindingContext: BindingContext? = null): D { +fun getOrCreateJvmSuspendFunctionView( + function: D, + bindingContext: BindingContext? = null, + dropSuspend: Boolean = false +): D { assert(function.isSuspend) { "Suspended function is expected, but $function was found" } @@ -220,6 +226,9 @@ fun getOrCreateJvmSuspendFunctionView(function: D, bind setPreserveSourceElement() setReturnType(function.builtIns.nullableAnyType) setValueParameters(it.valueParameters + continuationParameter) + if (dropSuspend) { + setDropSuspend() + } putUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION, it) } } @@ -433,3 +442,9 @@ fun InstructionAdapter.invokeDoResumeWithUnit(thisName: String) { fun Method.getImplForOpenMethod(ownerInternalName: String) = Method("$name\$suspendImpl", returnType, arrayOf(Type.getObjectType(ownerInternalName)) + argumentTypes) + +fun FunctionDescriptor.isSuspendLambdaOrLocalFunction() = this.isSuspend && when (this) { + is AnonymousFunctionDescriptor -> this.isSuspendLambda + is SimpleFunctionDescriptor -> this.visibility == Visibilities.LOCAL + else -> false +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java index a60c1d152d2..319d3225267 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.java @@ -170,7 +170,8 @@ public class KotlinTypeMapper { @NotNull private Type mapOwner(@NotNull DeclarationDescriptor descriptor, boolean publicFacade) { if (isLocalFunction(descriptor)) { - return asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor); + return asmTypeForAnonymousClass(bindingContext, + CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction((FunctionDescriptor) descriptor)); } if (descriptor instanceof ConstructorDescriptor) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt index 8c2e1ec1cda..6c6ef1f3752 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt @@ -72,7 +72,7 @@ object ModifierCheckerCore { INLINE_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, CLASS_ONLY), NOINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER), TAILREC_KEYWORD to EnumSet.of(FUNCTION), - SUSPEND_KEYWORD to EnumSet.of(MEMBER_FUNCTION, TOP_LEVEL_FUNCTION), + SUSPEND_KEYWORD to EnumSet.of(MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, LOCAL_FUNCTION), EXTERNAL_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, CLASS), ANNOTATION_KEYWORD to EnumSet.of(ANNOTATION_CLASS), CROSSINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER), diff --git a/compiler/testData/codegen/box/coroutines/localFunctions/anonymous/simple.kt b/compiler/testData/codegen/box/coroutines/localFunctions/anonymous/simple.kt new file mode 100644 index 00000000000..f47d96878ae --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/localFunctions/anonymous/simple.kt @@ -0,0 +1,23 @@ +// IGNORE_BACKEND_WITHOUT_CHECK: JVM, JS, NATIVE +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* + +suspend fun callLocal(): String { + val local = suspend fun() = "OK" + return local() +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res = "FAIL" + builder { + res = callLocal() + } + return res +} diff --git a/compiler/testData/codegen/box/coroutines/localFunctions/named/capturedParameters.kt b/compiler/testData/codegen/box/coroutines/localFunctions/named/capturedParameters.kt new file mode 100644 index 00000000000..9cc231cd31d --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/localFunctions/named/capturedParameters.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun callLocal(a: String, b: String): String { + suspend fun local() = suspendCoroutineOrReturn { + it.resume(a + b) + COROUTINE_SUSPENDED + } + return local() +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res = "FAIL" + builder { + res = callLocal("O", "K") + } + return res +} diff --git a/compiler/testData/codegen/box/coroutines/localFunctions/named/capturedVariables.kt b/compiler/testData/codegen/box/coroutines/localFunctions/named/capturedVariables.kt new file mode 100644 index 00000000000..c697ec3a6fb --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/localFunctions/named/capturedVariables.kt @@ -0,0 +1,28 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun callLocal(): String { + val a = "O" + val b = "K" + suspend fun local() = suspendCoroutineOrReturn { + it.resume(a + b) + COROUTINE_SUSPENDED + } + return local() +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res = "FAIL" + builder { + res = callLocal() + } + return res +} diff --git a/compiler/testData/codegen/box/coroutines/localFunctions/named/extension.kt b/compiler/testData/codegen/box/coroutines/localFunctions/named/extension.kt new file mode 100644 index 00000000000..4b858fea2f1 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/localFunctions/named/extension.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun callLocal(): String { + suspend fun String.local() = suspendCoroutineOrReturn { + it.resume(this) + COROUTINE_SUSPENDED + } + return "OK".local() +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res = "FAIL" + builder { + res = callLocal() + } + return res +} diff --git a/compiler/testData/codegen/box/coroutines/localFunctions/named/infix.kt b/compiler/testData/codegen/box/coroutines/localFunctions/named/infix.kt new file mode 100644 index 00000000000..eec52d1c34c --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/localFunctions/named/infix.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun callLocal(): String { + suspend infix fun String.local(a: String) = suspendCoroutineOrReturn { + it.resume(this + a) + COROUTINE_SUSPENDED + } + return "O" local "K" +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res = "FAIL" + builder { + res = callLocal() + } + return res +} diff --git a/compiler/testData/codegen/box/coroutines/localFunctions/named/insideLambda.kt b/compiler/testData/codegen/box/coroutines/localFunctions/named/insideLambda.kt new file mode 100644 index 00000000000..7f28448d169 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/localFunctions/named/insideLambda.kt @@ -0,0 +1,29 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun callLocal(): String { + val l: suspend () -> String = { + suspend fun local() = suspendCoroutineOrReturn { + it.resume("OK") + COROUTINE_SUSPENDED + } + local() + } + return l() +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res = "FAIL" + builder { + res = callLocal() + } + return res +} diff --git a/compiler/testData/codegen/box/coroutines/localFunctions/named/nestedLocals.kt b/compiler/testData/codegen/box/coroutines/localFunctions/named/nestedLocals.kt new file mode 100644 index 00000000000..f01ccf45375 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/localFunctions/named/nestedLocals.kt @@ -0,0 +1,37 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun callLocal(): String { + suspend fun local(): String { + suspend fun local(): String { + suspend fun local(): String { + suspend fun local(): String { + suspend fun local(): String { + return "OK" + } + return local() + } + return local() + } + return local() + } + return local() + } + return local() +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res = "FAIL" + builder { + res = callLocal() + } + return res +} diff --git a/compiler/testData/codegen/box/coroutines/localFunctions/named/simple.kt b/compiler/testData/codegen/box/coroutines/localFunctions/named/simple.kt new file mode 100644 index 00000000000..127a7420bf9 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/localFunctions/named/simple.kt @@ -0,0 +1,22 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* + +suspend fun callLocal(): String { + suspend fun local() = "OK" + return local() +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res = "FAIL" + builder { + res = callLocal() + } + return res +} diff --git a/compiler/testData/codegen/box/coroutines/localFunctions/named/simpleSuspensionPoint.kt b/compiler/testData/codegen/box/coroutines/localFunctions/named/simpleSuspensionPoint.kt new file mode 100644 index 00000000000..a3234a0067f --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/localFunctions/named/simpleSuspensionPoint.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun callLocal(): String { + suspend fun local() = suspendCoroutineOrReturn { + it.resume("OK") + COROUTINE_SUSPENDED + } + return local() +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res = "FAIL" + builder { + res = callLocal() + } + return res +} diff --git a/compiler/testData/codegen/box/coroutines/localFunctions/named/stateMachine.kt b/compiler/testData/codegen/box/coroutines/localFunctions/named/stateMachine.kt new file mode 100644 index 00000000000..d103e70fc68 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/localFunctions/named/stateMachine.kt @@ -0,0 +1,63 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +var result = "FAIL" +var i = 0 +var finished = false + +var proceed: () -> Unit = {} + +suspend fun suspendHere() = suspendCoroutine {c -> + i++ + proceed = { c.resume(Unit) } +} + +suspend fun callLocal() { + suspend fun local() { + suspendHere() + suspendHere() + suspendHere() + suspendHere() + suspendHere() + } + local() + local() +} + +fun builder(c: suspend () -> Unit) { + val continuation = object: Continuation { + override val context: CoroutineContext + get() = EmptyCoroutineContext + + override fun resume(value: Unit) { + proceed = { + result = "OK" + finished = true + } + } + + override fun resumeWithException(exception: Throwable) { + throw exception + } + } + c.startCoroutine(continuation) +} + +fun box(): String { + builder { + callLocal() + } + for (counter in 0 until 10) { + if (i != counter + 1) return "Expected ${counter + 1}, got $i" + proceed() + } + if (i != 10) return "FAIL $i" + if (finished) return "resume on root continuation is called" + proceed() + if (!finished) return "resume on root continuation is not called" + return result +} diff --git a/compiler/testData/codegen/box/coroutines/localFunctions/named/withArguments.kt b/compiler/testData/codegen/box/coroutines/localFunctions/named/withArguments.kt new file mode 100644 index 00000000000..3ad78a5ce7b --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/localFunctions/named/withArguments.kt @@ -0,0 +1,26 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* +import kotlin.coroutines.experimental.intrinsics.* + +suspend fun callLocal(a: String, b: String): String { + suspend fun local(a: String, b: String) = suspendCoroutineOrReturn { + it.resume(a + b) + COROUTINE_SUSPENDED + } + return local(a, b) +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res = "FAIL" + builder { + res = callLocal("O", "K") + } + return res +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/allMembersAllowed.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/allMembersAllowed.kt index 0c6a2a34296..226f4e72e45 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/allMembersAllowed.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/allMembersAllowed.kt @@ -58,7 +58,7 @@ fun String.test() { } } - suspend fun SuperInterface.fun1() { + suspend fun SuperInterface.fun1() { superFun() superExtFun() with("") { @@ -66,7 +66,7 @@ fun String.test() { superExtFun() } } - suspend fun RestrictedController.fun2() { + suspend fun RestrictedController.fun2() { superFun() superExtFun() memberFun() @@ -78,7 +78,7 @@ fun String.test() { memberExtFun() } } - suspend fun SubClass.fun3() { + suspend fun SubClass.fun3() { superFun() superExtFun() memberFun() diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/extensions.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/extensions.kt index c821e734a13..40f5d49687e 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/extensions.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/extensions.kt @@ -76,7 +76,7 @@ fun A.test() { } } - suspend fun SuperInterface.fun1() { + suspend fun SuperInterface.fun1() { extAny() memExtAny() extSuper() @@ -88,7 +88,7 @@ fun A.test() { memExtSuper() } } - suspend fun RestrictedController.fun2() { + suspend fun RestrictedController.fun2() { extAny() memExtAny() extSuper() @@ -105,7 +105,7 @@ fun A.test() { memExt() } } - suspend fun SubClass.fun3() { + suspend fun SubClass.fun3() { extAny() memExtAny() extSuper() diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/notRelatedFun.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/notRelatedFun.kt index 4b8125907ea..42fa77742b0 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/notRelatedFun.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension/notRelatedFun.kt @@ -43,7 +43,7 @@ fun A.test() { } } - suspend fun SuperInterface.fun1() { + suspend fun SuperInterface.fun1() { topLevel() member() with(A()) { @@ -51,7 +51,7 @@ fun A.test() { member() } } - suspend fun RestrictedController.fun2() { + suspend fun RestrictedController.fun2() { topLevel() member() with(A()) { @@ -59,7 +59,7 @@ fun A.test() { member() } } - suspend fun SubClass.fun3() { + suspend fun SubClass.fun3() { topLevel() member() with(A()) { diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/tailCalls/localFunctions.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/tailCalls/localFunctions.kt index ef284b46147..ed50fe169ab 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/tailCalls/localFunctions.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/tailCalls/localFunctions.kt @@ -2,16 +2,16 @@ suspend fun baz() = 1 suspend fun unit() {} suspend fun foo() { - suspend fun bar() { + suspend fun bar() { baz() return unit() } - suspend fun foobar1(): Int { + suspend fun foobar1(): Int { return baz() } - suspend fun foobar2() { + suspend fun foobar2() { return unit() } } diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 3b7c2b08e73..81612068f66 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -6557,6 +6557,99 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes } } + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LocalFunctions extends AbstractIrBlackBoxCodegenTest { + public void testAllFilesPresentInLocalFunctions() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/localFunctions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions/anonymous") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Anonymous extends AbstractIrBlackBoxCodegenTest { + @TestMetadata("simple.kt") + public void ignoreSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/anonymous/simple.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInAnonymous() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/localFunctions/anonymous"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + } + + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Named extends AbstractIrBlackBoxCodegenTest { + public void testAllFilesPresentInNamed() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/localFunctions/named"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("capturedParameters.kt") + public void testCapturedParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/capturedParameters.kt"); + doTest(fileName); + } + + @TestMetadata("capturedVariables.kt") + public void testCapturedVariables() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/capturedVariables.kt"); + doTest(fileName); + } + + @TestMetadata("extension.kt") + public void testExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/extension.kt"); + doTest(fileName); + } + + @TestMetadata("infix.kt") + public void testInfix() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/infix.kt"); + doTest(fileName); + } + + @TestMetadata("insideLambda.kt") + public void testInsideLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/insideLambda.kt"); + doTest(fileName); + } + + @TestMetadata("nestedLocals.kt") + public void testNestedLocals() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/nestedLocals.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/simple.kt"); + doTest(fileName); + } + + @TestMetadata("simpleSuspensionPoint.kt") + public void testSimpleSuspensionPoint() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/simpleSuspensionPoint.kt"); + doTest(fileName); + } + + @TestMetadata("stateMachine.kt") + public void testStateMachine() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/stateMachine.kt"); + doTest(fileName); + } + + @TestMetadata("withArguments.kt") + public void testWithArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/withArguments.kt"); + doTest(fileName); + } + } + } + @TestMetadata("compiler/testData/codegen/box/coroutines/multiModule") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 74355942c65..4e9941a64b0 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -6557,6 +6557,99 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { } } + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LocalFunctions extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInLocalFunctions() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/localFunctions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions/anonymous") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Anonymous extends AbstractBlackBoxCodegenTest { + @TestMetadata("simple.kt") + public void ignoreSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/anonymous/simple.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInAnonymous() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/localFunctions/anonymous"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + } + + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Named extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInNamed() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/localFunctions/named"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("capturedParameters.kt") + public void testCapturedParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/capturedParameters.kt"); + doTest(fileName); + } + + @TestMetadata("capturedVariables.kt") + public void testCapturedVariables() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/capturedVariables.kt"); + doTest(fileName); + } + + @TestMetadata("extension.kt") + public void testExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/extension.kt"); + doTest(fileName); + } + + @TestMetadata("infix.kt") + public void testInfix() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/infix.kt"); + doTest(fileName); + } + + @TestMetadata("insideLambda.kt") + public void testInsideLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/insideLambda.kt"); + doTest(fileName); + } + + @TestMetadata("nestedLocals.kt") + public void testNestedLocals() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/nestedLocals.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/simple.kt"); + doTest(fileName); + } + + @TestMetadata("simpleSuspensionPoint.kt") + public void testSimpleSuspensionPoint() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/simpleSuspensionPoint.kt"); + doTest(fileName); + } + + @TestMetadata("stateMachine.kt") + public void testStateMachine() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/stateMachine.kt"); + doTest(fileName); + } + + @TestMetadata("withArguments.kt") + public void testWithArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/withArguments.kt"); + doTest(fileName); + } + } + } + @TestMetadata("compiler/testData/codegen/box/coroutines/multiModule") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index e1347f0ac49..7a30b131cab 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -6557,6 +6557,99 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes } } + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LocalFunctions extends AbstractLightAnalysisModeTest { + public void testAllFilesPresentInLocalFunctions() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/localFunctions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions/anonymous") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Anonymous extends AbstractLightAnalysisModeTest { + @TestMetadata("simple.kt") + public void ignoreSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/anonymous/simple.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInAnonymous() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/localFunctions/anonymous"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + } + + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Named extends AbstractLightAnalysisModeTest { + public void testAllFilesPresentInNamed() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/localFunctions/named"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("capturedParameters.kt") + public void testCapturedParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/capturedParameters.kt"); + doTest(fileName); + } + + @TestMetadata("capturedVariables.kt") + public void testCapturedVariables() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/capturedVariables.kt"); + doTest(fileName); + } + + @TestMetadata("extension.kt") + public void testExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/extension.kt"); + doTest(fileName); + } + + @TestMetadata("infix.kt") + public void testInfix() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/infix.kt"); + doTest(fileName); + } + + @TestMetadata("insideLambda.kt") + public void testInsideLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/insideLambda.kt"); + doTest(fileName); + } + + @TestMetadata("nestedLocals.kt") + public void testNestedLocals() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/nestedLocals.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/simple.kt"); + doTest(fileName); + } + + @TestMetadata("simpleSuspensionPoint.kt") + public void testSimpleSuspensionPoint() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/simpleSuspensionPoint.kt"); + doTest(fileName); + } + + @TestMetadata("stateMachine.kt") + public void testStateMachine() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/stateMachine.kt"); + doTest(fileName); + } + + @TestMetadata("withArguments.kt") + public void testWithArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/withArguments.kt"); + doTest(fileName); + } + } + } + @TestMetadata("compiler/testData/codegen/box/coroutines/multiModule") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/FunctionDescriptor.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/FunctionDescriptor.java index a41993e8d02..537006ee9e6 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/FunctionDescriptor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/FunctionDescriptor.java @@ -144,6 +144,9 @@ public interface FunctionDescriptor extends CallableMemberDescriptor { @NotNull CopyBuilder setDropOriginalInContainingParts(); + @NotNull + CopyBuilder setDropSuspend(); + @NotNull CopyBuilder setHiddenToOvercomeSignatureClash(); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java index 6ba1d21e510..9577ad2a522 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java @@ -372,6 +372,7 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo private Map, Object> userDataMap = new LinkedHashMap, Object>(); private Boolean newHasSynthesizedParameterNames = null; protected boolean justForTypeSubstitution = false; + private boolean dropSuspend = false; public CopyConfiguration( @NotNull TypeSubstitution substitution, @@ -500,6 +501,13 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo return this; } + @Override + @NotNull + public CopyConfiguration setDropSuspend() { + this.dropSuspend = true; + return this; + } + @Override @NotNull public CopyConfiguration setHiddenToOvercomeSignatureClash() { @@ -664,7 +672,11 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo substitutedDescriptor.setExternal(isExternal); substitutedDescriptor.setInline(isInline); substitutedDescriptor.setTailrec(isTailrec); - substitutedDescriptor.setSuspend(isSuspend); + if (configuration.dropSuspend) { + substitutedDescriptor.setSuspend(false); + } else { + substitutedDescriptor.setSuspend(isSuspend); + } substitutedDescriptor.setExpect(isExpect); substitutedDescriptor.setActual(isActual); substitutedDescriptor.setHasStableParameterNames(hasStableParameterNames); diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/error/ErrorSimpleFunctionDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/types/error/ErrorSimpleFunctionDescriptorImpl.java index 025c460c9f6..7ffc1929afd 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/error/ErrorSimpleFunctionDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/types/error/ErrorSimpleFunctionDescriptorImpl.java @@ -168,6 +168,12 @@ public class ErrorSimpleFunctionDescriptorImpl extends SimpleFunctionDescriptorI return this; } + @NotNull + @Override + public CopyBuilder setDropSuspend() { + return this; + } + @NotNull @Override public CopyBuilder setHiddenToOvercomeSignatureClash() { 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 aea8d2c98fa..03243d4f717 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 @@ -7852,6 +7852,99 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { } } + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LocalFunctions extends AbstractJsCodegenBoxTest { + public void testAllFilesPresentInLocalFunctions() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/localFunctions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); + } + + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions/anonymous") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Anonymous extends AbstractJsCodegenBoxTest { + @TestMetadata("simple.kt") + public void ignoreSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/anonymous/simple.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInAnonymous() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/localFunctions/anonymous"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); + } + } + + @TestMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Named extends AbstractJsCodegenBoxTest { + public void testAllFilesPresentInNamed() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/localFunctions/named"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); + } + + @TestMetadata("capturedParameters.kt") + public void testCapturedParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/capturedParameters.kt"); + doTest(fileName); + } + + @TestMetadata("capturedVariables.kt") + public void testCapturedVariables() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/capturedVariables.kt"); + doTest(fileName); + } + + @TestMetadata("extension.kt") + public void testExtension() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/extension.kt"); + doTest(fileName); + } + + @TestMetadata("infix.kt") + public void testInfix() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/infix.kt"); + doTest(fileName); + } + + @TestMetadata("insideLambda.kt") + public void testInsideLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/insideLambda.kt"); + doTest(fileName); + } + + @TestMetadata("nestedLocals.kt") + public void testNestedLocals() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/nestedLocals.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/simple.kt"); + doTest(fileName); + } + + @TestMetadata("simpleSuspensionPoint.kt") + public void testSimpleSuspensionPoint() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/simpleSuspensionPoint.kt"); + doTest(fileName); + } + + @TestMetadata("stateMachine.kt") + public void testStateMachine() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/stateMachine.kt"); + doTest(fileName); + } + + @TestMetadata("withArguments.kt") + public void testWithArguments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/localFunctions/named/withArguments.kt"); + doTest(fileName); + } + } + } + @TestMetadata("compiler/testData/codegen/box/coroutines/multiModule") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)