diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 04c0c133ede..357d1095df4 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2229,9 +2229,7 @@ public class ExpressionCodegen extends KtVisitor impleme @NotNull private Type getReturnTypeForNonLocalReturn(DeclarationDescriptor elementDescriptor) { - return (elementDescriptor instanceof AnonymousFunctionDescriptor - && ((AnonymousFunctionDescriptor) elementDescriptor).isCoroutine()) - || (elementDescriptor instanceof FunctionDescriptor && ((FunctionDescriptor) elementDescriptor).isSuspend()) + return elementDescriptor instanceof FunctionDescriptor && ((FunctionDescriptor) elementDescriptor).isSuspend() ? getBoxedReturnTypeForSuspend((FunctionDescriptor) elementDescriptor) : typeMapper.mapReturnType((CallableDescriptor) elementDescriptor); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt index 4fb813acf20..abe143fe798 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt @@ -827,7 +827,7 @@ class ControlFlowInformationProvider private constructor( val isUsedAsExpression = instruction.owner.getUsages(instruction.outputValue).isNotEmpty() if (!isUsedAsExpression || !instruction.isTailCall(enclosingSuspendFunction) || isInsideTry(element)) { - trace.report(Errors.SUSPENSION_CALL_MUST_BE_USED_AS_RETURN_VALUE.on(element)) + trace.record(BindingContext.CONTAINS_NON_TAIL_SUSPEND_CALLS, currentFunction.original) } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/coroutines/coroutineUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/coroutines/coroutineUtil.kt index 008090a7468..143c2b0b0fe 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/coroutines/coroutineUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/coroutines/coroutineUtil.kt @@ -21,6 +21,6 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor -val CallableDescriptor.isSuspendLambda get() = this is AnonymousFunctionDescriptor && this.isCoroutine +val CallableDescriptor.isSuspendLambda get() = this is AnonymousFunctionDescriptor && this.isSuspend val ValueParameterDescriptor.hasSuspendFunctionType get() = returnType?.isSuspendFunctionType == true diff --git a/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/AnonymousFunctionDescriptor.java b/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/AnonymousFunctionDescriptor.java index c7af19ed2a1..da8c2adcce6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/AnonymousFunctionDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/AnonymousFunctionDescriptor.java @@ -23,20 +23,21 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.name.Name; public class AnonymousFunctionDescriptor extends SimpleFunctionDescriptorImpl { - private final boolean isCoroutine; + private final boolean isSuspend; public AnonymousFunctionDescriptor( @NotNull DeclarationDescriptor containingDeclaration, @NotNull Annotations annotations, @NotNull Kind kind, @NotNull SourceElement source, - boolean isCoroutine + boolean isSuspend ) { super(containingDeclaration, null, annotations, Name.special(""), kind, source); - this.isCoroutine = isCoroutine; + this.isSuspend = isSuspend; } - public boolean isCoroutine() { - return isCoroutine; + @Override + public boolean isSuspend() { + return isSuspend; } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 56a92bfd71b..8219aa5badc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -891,7 +891,6 @@ public interface Errors { DiagnosticFactory0 NON_LOCAL_SUSPENSION_POINT = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 ILLEGAL_SUSPEND_FUNCTION_CALL = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL = DiagnosticFactory0.create(ERROR); - DiagnosticFactory0 SUSPENSION_CALL_MUST_BE_USED_AS_RETURN_VALUE = DiagnosticFactory0.create(ERROR); // Error sets diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index dbdbce6cb0f..bdf7861ef5a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -891,7 +891,6 @@ public class DefaultErrorMessages { MAP.put(NON_LOCAL_SUSPENSION_POINT, "Suspension functions can be called only within coroutine body"); MAP.put(ILLEGAL_SUSPEND_FUNCTION_CALL, "Suspend functions are only allowed to be called from a coroutine or another suspend function"); MAP.put(ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL, "Restricted suspending functions can only invoke member or extension suspending functions on their restricted coroutine scope"); - MAP.put(SUSPENSION_CALL_MUST_BE_USED_AS_RETURN_VALUE, "Only tail calls are allowed to another suspension function, and these calls must be used as return values"); MAP.setImmutable(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java index 2ff8827acfe..7cdb7c20b9b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java @@ -135,8 +135,8 @@ public interface BindingContext { WritableSlice> LOOP_RANGE_NEXT_RESOLVED_CALL = Slices.createSimpleSlice(); WritableSlice> RETURN_HANDLE_RESULT_RESOLVED_CALL = Slices.createSimpleSlice(); - WritableSlice ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT = Slices.createSimpleSlice(); - WritableSlice ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL = Slices.createSimpleSlice(); + WritableSlice ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL = Slices.createSimpleSlice(); + WritableSlice CONTAINS_NON_TAIL_SUSPEND_CALLS = Slices.createSimpleSetSlice(); WritableSlice> DELEGATED_PROPERTY_RESOLVED_CALL = Slices.createSimpleSlice(); WritableSlice DELEGATED_PROPERTY_CALL = Slices.createSimpleSlice(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/coroutineCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/coroutineCallChecker.kt index b6f9ff6348c..06fcb58bcbd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/coroutineCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/coroutineCallChecker.kt @@ -20,10 +20,8 @@ import com.intellij.psi.PsiElement import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.coroutines.hasSuspendFunctionType -import org.jetbrains.kotlin.coroutines.isSuspendLambda import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.Errors @@ -47,40 +45,26 @@ object CoroutineSuspendCallChecker : CallChecker { val descriptor = resolvedCall.candidateDescriptor as? SimpleFunctionDescriptor ?: return if (!descriptor.isSuspend) return - val (closestSuspendLambdaScope, closestSuspensionLambdaDescriptor) = + val enclosingSuspendFunction = context.scope .parentsWithSelf.firstOrNull { it is LexicalScope && it.kind == LexicalScopeKind.FUNCTION_INNER_SCOPE && - it.ownerDescriptor.safeAs()?.isSuspendLambda == true - }?.let { it to it.cast().ownerDescriptor.cast() } - ?: null to null - - val enclosingSuspendFunction = - context.scope.parentsWithSelf.filterIsInstance().takeWhile { it != closestSuspendLambdaScope } - .firstOrNull { - (it.ownerDescriptor as? FunctionDescriptor)?.isSuspend == true - }?.ownerDescriptor as? SimpleFunctionDescriptor + it.ownerDescriptor.safeAs()?.isSuspend == true + }?.cast()?.ownerDescriptor?.cast() when { enclosingSuspendFunction != null -> { - // Tail calls checks happen during control flow analysis - // Here we only record enclosing function mapping (for backends purposes) - context.trace.record(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.call, enclosingSuspendFunction) - - checkRestrictsSuspension(enclosingSuspendFunction, resolvedCall, reportOn, context) - } - closestSuspensionLambdaDescriptor != null -> { val callElement = resolvedCall.call.callElement as KtExpression - if (!InlineUtil.checkNonLocalReturnUsage(closestSuspensionLambdaDescriptor, callElement, context.resolutionContext)) { + if (!InlineUtil.checkNonLocalReturnUsage(enclosingSuspendFunction, callElement, context.resolutionContext)) { context.trace.report(Errors.NON_LOCAL_SUSPENSION_POINT.on(reportOn)) } context.trace.record( - BindingContext.ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT, resolvedCall.call, closestSuspensionLambdaDescriptor + BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.call, enclosingSuspendFunction ) - checkRestrictsSuspension(closestSuspensionLambdaDescriptor, resolvedCall, reportOn, context) + checkRestrictsSuspension(enclosingSuspendFunction, resolvedCall, reportOn, context) } else -> { context.trace.report(Errors.ILLEGAL_SUSPEND_FUNCTION_CALL.on(reportOn)) diff --git a/compiler/testData/diagnostics/tests/coroutines/tailCalls/forbidden.kt b/compiler/testData/diagnostics/tests/coroutines/tailCalls/forbidden.kt index c454baf2b25..5ab0bed44ce 100644 --- a/compiler/testData/diagnostics/tests/coroutines/tailCalls/forbidden.kt +++ b/compiler/testData/diagnostics/tests/coroutines/tailCalls/forbidden.kt @@ -5,15 +5,15 @@ import kotlin.coroutines.intrinsics.* fun nonSuspend() {} suspend fun foo() { - suspendCoroutineOrReturn { x: Continuation -> } + suspendCoroutineOrReturn { x: Continuation -> } nonSuspend() } suspend fun unitSuspend() { - suspendCoroutineOrReturn { x: Continuation -> } + suspendCoroutineOrReturn { x: Continuation -> } } suspend fun baz(): Int = run { - suspendCoroutineOrReturn { x: Continuation -> } + suspendCoroutineOrReturn { x: Continuation -> } } diff --git a/compiler/testData/diagnostics/tests/coroutines/tailCalls/localFunctions.kt b/compiler/testData/diagnostics/tests/coroutines/tailCalls/localFunctions.kt index 1f3218ce667..ed50fe169ab 100644 --- a/compiler/testData/diagnostics/tests/coroutines/tailCalls/localFunctions.kt +++ b/compiler/testData/diagnostics/tests/coroutines/tailCalls/localFunctions.kt @@ -3,7 +3,7 @@ suspend fun unit() {} suspend fun foo() { suspend fun bar() { - baz() + baz() return unit() } diff --git a/compiler/testData/diagnostics/tests/coroutines/tailCalls/nothingTypedSuspendFunction.kt b/compiler/testData/diagnostics/tests/coroutines/tailCalls/nothingTypedSuspendFunction.kt index b4f784f23b9..3404ba5ba29 100644 --- a/compiler/testData/diagnostics/tests/coroutines/tailCalls/nothingTypedSuspendFunction.kt +++ b/compiler/testData/diagnostics/tests/coroutines/tailCalls/nothingTypedSuspendFunction.kt @@ -2,7 +2,7 @@ import kotlin.coroutines.* import kotlin.coroutines.intrinsics.* -suspend fun suspendLogAndThrow(exception: Throwable): Nothing = suspendCoroutineOrReturn { c -> +suspend fun suspendLogAndThrow(exception: Throwable): Nothing = suspendCoroutineOrReturn { c -> c.resumeWithException(exception) SUSPENDED_MARKER -} +} diff --git a/compiler/testData/diagnostics/tests/coroutines/tailCalls/recursive.kt b/compiler/testData/diagnostics/tests/coroutines/tailCalls/recursive.kt index 3684c3c556f..9322a658a74 100644 --- a/compiler/testData/diagnostics/tests/coroutines/tailCalls/recursive.kt +++ b/compiler/testData/diagnostics/tests/coroutines/tailCalls/recursive.kt @@ -1,5 +1,5 @@ suspend fun unit1() { - unit1() + unit1() } suspend fun unit2() { @@ -13,6 +13,6 @@ suspend fun int1(): Int { suspend fun int2(): Int = int2() suspend fun int3(): Int { - int3() + int3() return int3() } diff --git a/compiler/testData/diagnostics/tests/coroutines/tailCalls/tryCatch.kt b/compiler/testData/diagnostics/tests/coroutines/tailCalls/tryCatch.kt index ab487edc8f1..41d381a89b7 100644 --- a/compiler/testData/diagnostics/tests/coroutines/tailCalls/tryCatch.kt +++ b/compiler/testData/diagnostics/tests/coroutines/tailCalls/tryCatch.kt @@ -8,15 +8,15 @@ suspend fun baz(): Int = 1 suspend fun tryCatch(): Int { return try { - suspendCoroutineOrReturn { x: Continuation -> } + suspendCoroutineOrReturn { x: Continuation -> } } catch (e: Exception) { - baz() // another suspend function + baz() // another suspend function } } suspend fun tryFinally(): Int { return try { - suspendCoroutineOrReturn { x: Continuation -> } + suspendCoroutineOrReturn { x: Continuation -> } } finally { nonSuspend() } @@ -26,16 +26,16 @@ suspend fun returnInFinally(): Int { try { } finally { // Probably this is too restrictive, but it does not matter much - return baz() + return baz() } } suspend fun tryCatchFinally(): Int { return try { - suspendCoroutineOrReturn { x: Continuation -> } + suspendCoroutineOrReturn { x: Continuation -> } } catch (e: Exception) { - baz() // another suspend function + baz() // another suspend function } finally { - baz() + baz() } } diff --git a/js/js.frontend/src/org/jetbrains/kotlin/js/descriptorUtils/descriptorUtils.kt b/js/js.frontend/src/org/jetbrains/kotlin/js/descriptorUtils/descriptorUtils.kt index 991cdc19c97..53ec5857f66 100644 --- a/js/js.frontend/src/org/jetbrains/kotlin/js/descriptorUtils/descriptorUtils.kt +++ b/js/js.frontend/src/org/jetbrains/kotlin/js/descriptorUtils/descriptorUtils.kt @@ -54,4 +54,4 @@ fun KotlinType.getJetTypeFqName(printTypeArguments: Boolean): String { fun ClassDescriptor.hasPrimaryConstructor(): Boolean = unsubstitutedPrimaryConstructor != null val DeclarationDescriptor.isCoroutineLambda: Boolean - get() = this is AnonymousFunctionDescriptor && isCoroutine \ No newline at end of file + get() = this is AnonymousFunctionDescriptor && isSuspend diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java index 74ca7eedbd1..39facf9349c 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/utils/TranslationUtils.java @@ -339,7 +339,7 @@ public final class TranslationUtils { @NotNull public static JsExpression translateContinuationArgument(@NotNull TranslationContext context, @NotNull ResolvedCall resolvedCall) { CallableDescriptor continuationDescriptor = - context.bindingContext().get(BindingContext.ENCLOSING_SUSPEND_LAMBDA_FOR_SUSPENSION_POINT, resolvedCall.getCall()); + context.bindingContext().get(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall()); if (continuationDescriptor == null) { continuationDescriptor = getEnclosingContinuationParameter(context);