From a34c9c2580541ddb97b336ea6c48a3c5f7524e9e Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 24 Nov 2016 15:18:44 +0300 Subject: [PATCH] Support new suspend convention in frontend #KT-14924 In Progress --- .../kotlin/resolve/BindingContext.java | 4 + .../kotlin/resolve/TargetPlatform.kt | 1 - .../calls/checkers/coroutineCallChecker.kt | 37 ++++++-- .../checkers/SuspendModifierChecker.kt | 85 ------------------- .../calls/tower/ScopeTowerProcessors.kt | 16 +--- .../kotlin/resolve/calls/tower/TowerLevels.kt | 14 +-- .../kotlin/resolve/coroutine/coroutineUtil.kt | 30 ------- .../irrelevantSuspendDeclarations.kt | 11 +-- .../irrelevantSuspendDeclarations.txt | 4 +- .../tests/coroutines/nonLocalSuspension.kt | 8 +- .../tests/coroutines/nonLocalSuspension.txt | 4 +- .../tests/coroutines/suspendApplicability.kt | 41 +++------ .../tests/coroutines/suspendApplicability.txt | 24 +++--- .../coroutines/suspendExtensionFunctions.kt | 60 ------------- .../coroutines/suspendExtensionFunctions.txt | 18 ---- .../coroutines/suspendExternalFunctions.kt | 53 ++++++++++++ .../coroutines/suspendExternalFunctions.txt | 18 ++++ .../tests/coroutines/suspendFunctions.kt | 21 ++--- .../tests/coroutines/suspendFunctions.txt | 10 +-- .../tests/coroutines/tryCatchLambda.kt | 2 +- .../tests/coroutines/tryCatchLambda.txt | 2 +- .../tests/coroutines/unsupported.kt | 4 +- .../tests/coroutines/unsupported.txt | 2 +- .../checkers/DiagnosticsTestGenerated.java | 6 +- .../checker/infos/suspendApplicability.kt | 43 ---------- .../checkers/PsiCheckerTestGenerated.java | 6 -- 26 files changed, 168 insertions(+), 356 deletions(-) delete mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/SuspendModifierChecker.kt delete mode 100644 compiler/testData/diagnostics/tests/coroutines/suspendExtensionFunctions.kt delete mode 100644 compiler/testData/diagnostics/tests/coroutines/suspendExtensionFunctions.txt create mode 100644 compiler/testData/diagnostics/tests/coroutines/suspendExternalFunctions.kt create mode 100644 compiler/testData/diagnostics/tests/coroutines/suspendExternalFunctions.txt delete mode 100644 idea/testData/checker/infos/suspendApplicability.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java index 0d1ad78f881..fc5b0ecc297 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContext.java @@ -36,6 +36,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue; import org.jetbrains.kotlin.resolve.calls.smartcasts.ExplicitSmartCasts; import org.jetbrains.kotlin.resolve.calls.smartcasts.ImplicitSmartCasts; import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; +import org.jetbrains.kotlin.resolve.coroutine.CoroutineReceiverValue; import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics; import org.jetbrains.kotlin.resolve.scopes.LexicalScope; import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier; @@ -135,6 +136,9 @@ public interface BindingContext { WritableSlice> LOOP_RANGE_NEXT_RESOLVED_CALL = Slices.createSimpleSlice(); WritableSlice> RETURN_HANDLE_RESULT_RESOLVED_CALL = Slices.createSimpleSlice(); + WritableSlice COROUTINE_RECEIVER_FOR_SUSPENSION_POINT = Slices.createSimpleSlice(); + WritableSlice ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL = Slices.createSimpleSlice(); + WritableSlice> DELEGATED_PROPERTY_RESOLVED_CALL = Slices.createSimpleSlice(); WritableSlice DELEGATED_PROPERTY_CALL = Slices.createSimpleSlice(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index d799a9339db..f0b07c847ea 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -64,7 +64,6 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf( UnderscoreChecker, InlineParameterChecker, InfixModifierChecker(), - SuspendModifierChecker, CoroutineModifierChecker, SinceKotlinAnnotationValueChecker, ReifiedTypeParameterAnnotationChecker() 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 eef832297f9..8995e512fc1 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 @@ -19,22 +19,47 @@ package org.jetbrains.kotlin.resolve.calls.checkers import com.intellij.psi.PsiElement import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.coroutine.CoroutineReceiverValue import org.jetbrains.kotlin.resolve.inline.InlineUtil +import org.jetbrains.kotlin.resolve.scopes.LexicalScope +import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy +import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf object CoroutineSuspendCallChecker : CallChecker { override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { - val descriptor = resolvedCall.candidateDescriptor as? FunctionDescriptor ?: return - if (!descriptor.isSuspend || descriptor.initialSignatureDescriptor == null) return + val descriptor = resolvedCall.candidateDescriptor as? SimpleFunctionDescriptor ?: return + if (!descriptor.isSuspend) return - val dispatchReceiverOwner = (resolvedCall.dispatchReceiver as? CoroutineReceiverValue)?.declarationDescriptor ?: return - val callElement = resolvedCall.call.callElement as KtExpression + val closestCoroutineReceiver = + context.scope.getImplicitReceiversHierarchy().firstOrNull { it.value is CoroutineReceiverValue }?.value as CoroutineReceiverValue? - if (!InlineUtil.checkNonLocalReturnUsage(dispatchReceiverOwner, callElement, context.resolutionContext)) { - context.trace.report(Errors.NON_LOCAL_SUSPENSION_POINT.on(reportOn)) + val enclosingSuspendFunction = + context.scope.parentsWithSelf.filterIsInstance().takeWhile { + closestCoroutineReceiver == null || it.implicitReceiver?.value != closestCoroutineReceiver + }.firstOrNull { + (it.ownerDescriptor as? FunctionDescriptor)?.isSuspend == true + }?.ownerDescriptor as? SimpleFunctionDescriptor + + when { + enclosingSuspendFunction != null -> { + // TODO: check if tail call + context.trace.record(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.call, enclosingSuspendFunction) + } + closestCoroutineReceiver != null -> { + + val callElement = resolvedCall.call.callElement as KtExpression + + if (!InlineUtil.checkNonLocalReturnUsage(closestCoroutineReceiver.declarationDescriptor, callElement, context.resolutionContext)) { + context.trace.report(Errors.NON_LOCAL_SUSPENSION_POINT.on(reportOn)) + } + + context.trace.record(BindingContext.COROUTINE_RECEIVER_FOR_SUSPENSION_POINT, resolvedCall.call, closestCoroutineReceiver) + } } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/SuspendModifierChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/SuspendModifierChecker.kt deleted file mode 100644 index 90ea04f442b..00000000000 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/SuspendModifierChecker.kt +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2010-2016 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. - */ - -package org.jetbrains.kotlin.resolve.checkers - -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.coroutines.isValidContinuation -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.diagnostics.DiagnosticSink -import org.jetbrains.kotlin.diagnostics.Errors -import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.KtDeclaration -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.types.typeUtil.isUnit -import org.jetbrains.kotlin.utils.sure - -object SuspendModifierChecker : SimpleDeclarationChecker { - private val ALLOW_SUSPEND_EXTENSIONS_ANNOTATION_FQ_NAME = - KotlinBuiltIns.COROUTINES_PACKAGE_FQ_NAME.child(Name.identifier("AllowSuspendExtensions")) - - override fun check( - declaration: KtDeclaration, - descriptor: DeclarationDescriptor, - diagnosticHolder: DiagnosticSink, - bindingContext: BindingContext - ) { - val functionDescriptor = descriptor as? FunctionDescriptor ?: return - if (!functionDescriptor.isSuspend) return - - val suspendModifierElement = declaration.modifierList?.getModifier(KtTokens.SUSPEND_KEYWORD).sure { declaration.text } - fun report(message: String) { - diagnosticHolder.report(Errors.INAPPLICABLE_MODIFIER.on(suspendModifierElement, KtTokens.SUSPEND_KEYWORD, message)) - } - - if (functionDescriptor.dispatchReceiverParameter == null) { - if (functionDescriptor.extensionReceiverParameter == null) { - report("function must be either a class member or an extension") - return - } - - val classDescriptor = - functionDescriptor.extensionReceiverParameter!!.type.constructor.declarationDescriptor as? ClassDescriptor - if (classDescriptor == null) { - report("function must be an extension to class") - return - } - - if (!classDescriptor.annotations.hasAnnotation(ALLOW_SUSPEND_EXTENSIONS_ANNOTATION_FQ_NAME)) { - report("controller class must be annotated with AllowSuspendExtensions annotation") - return - } - } - - val continuationParameterType = functionDescriptor.valueParameters.lastOrNull()?.type - val isValidContinuation = continuationParameterType?.isValidContinuation() ?: false - if (!isValidContinuation) { - report("last parameter of suspend function should have a type of Continuation") - return - } - - if (continuationParameterType?.arguments?.firstOrNull()?.isStarProjection == true) { - report("Continuation<*> is prohibited as a last parameter of suspend function") - } - - if (functionDescriptor.returnType?.isUnit() != true) { - report("return type of suspension function must be a kotlin.Unit, but ${functionDescriptor.returnType} was found") - } - } -} diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt index c67f83a8272..28426206855 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerProcessors.kt @@ -21,9 +21,9 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind -import org.jetbrains.kotlin.resolve.coroutine.CoroutineReceiverValue -import org.jetbrains.kotlin.resolve.coroutine.createCoroutineSuspensionFunctionView -import org.jetbrains.kotlin.resolve.scopes.receivers.* +import org.jetbrains.kotlin.resolve.scopes.receivers.DetailedReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo import org.jetbrains.kotlin.utils.addToStdlib.check @@ -109,14 +109,6 @@ private class NoExplicitReceiverScopeTowerProcessor> createProcessorWithReceiverValueOr else { create(explicitReceiver as ReceiverValueWithSmartCastInfo?) } -} \ No newline at end of file +} diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt index d75b7214b45..f8e5f8ac58a 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/tower/TowerLevels.kt @@ -24,14 +24,15 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.smartcasts.getReceiverValueWithSmartCast import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForTypeAliasObject -import org.jetbrains.kotlin.resolve.coroutine.CoroutineReceiverValue -import org.jetbrains.kotlin.resolve.coroutine.createCoroutineSuspensionFunctionView import org.jetbrains.kotlin.resolve.descriptorUtil.HIDES_MEMBERS_NAME_LIST import org.jetbrains.kotlin.resolve.descriptorUtil.hasClassValueDescriptor import org.jetbrains.kotlin.resolve.descriptorUtil.hasHidesMembersAnnotation import org.jetbrains.kotlin.resolve.descriptorUtil.hasLowPriorityInOverloadResolution import org.jetbrains.kotlin.resolve.scopes.* -import org.jetbrains.kotlin.resolve.scopes.receivers.* +import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.QualifierReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo import org.jetbrains.kotlin.resolve.scopes.utils.collectFunctions import org.jetbrains.kotlin.resolve.scopes.utils.collectVariables import org.jetbrains.kotlin.resolve.selectMostSpecificInEachOverridableGroup @@ -118,13 +119,6 @@ internal class ReceiverScopeTowerLevel( } } - if (receiverValue is CoroutineReceiverValue) { - result.addAll(result.mapNotNull { - val suspensionFunctionView = it.descriptor.createCoroutineSuspensionFunctionView() ?: return@mapNotNull null - createCandidateDescriptor(suspensionFunctionView, dispatchReceiver) - }) - } - return result } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/coroutine/coroutineUtil.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/coroutine/coroutineUtil.kt index aca35da27b8..53a197ca8d0 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/coroutine/coroutineUtil.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/coroutine/coroutineUtil.kt @@ -17,37 +17,7 @@ package org.jetbrains.kotlin.resolve.coroutine import org.jetbrains.kotlin.descriptors.CallableDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver import org.jetbrains.kotlin.types.KotlinType -val SUSPENSION_POINT_KEY: FunctionDescriptor.UserDataKey = object : FunctionDescriptor.UserDataKey {} -val REPLACED_SUSPENSION_POINT_KEY: FunctionDescriptor.UserDataKey = object : FunctionDescriptor.UserDataKey {} - -// Returns suspension function as it's visible within coroutines: -// E.g. `fun await(f: CompletableFuture): V` instead of `fun await(f: CompletableFuture, machine: Continuation): Unit` -fun D.createCoroutineSuspensionFunctionView(): D? { - if (this !is SimpleFunctionDescriptor) return null - if (!isSuspend) return null - val returnType = getSuspensionPointReturnType() ?: return null - - val newOriginal = - if (original !== this) - original.createCoroutineSuspensionFunctionView() - else null - - @Suppress("UNCHECKED_CAST") - return newCopyBuilder().apply { - setReturnType(returnType) - setOriginal(newOriginal) - setValueParameters(valueParameters.subList(0, valueParameters.size - 1)) - setSignatureChange() - setPreserveSourceElement() - putUserData(SUSPENSION_POINT_KEY, true) - }.build()!! as D -} - -fun SimpleFunctionDescriptor.getSuspensionPointReturnType(): KotlinType? = valueParameters.lastOrNull()?.returnType?.arguments?.getOrNull(0)?.type - class CoroutineReceiverValue(callableDescriptor: CallableDescriptor, receiverType: KotlinType) : ExtensionReceiver(callableDescriptor, receiverType) diff --git a/compiler/testData/diagnostics/tests/coroutines/irrelevantSuspendDeclarations.kt b/compiler/testData/diagnostics/tests/coroutines/irrelevantSuspendDeclarations.kt index 4e4a8c83d0b..1d31aad16fb 100644 --- a/compiler/testData/diagnostics/tests/coroutines/irrelevantSuspendDeclarations.kt +++ b/compiler/testData/diagnostics/tests/coroutines/irrelevantSuspendDeclarations.kt @@ -1,13 +1,11 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER // !CHECK_TYPE class Controller { - suspend fun suspendHere(a: String, x: Continuation) { - } + suspend fun suspendHere(a: String) = 1 } class A { - suspend fun suspendHere(a: Int, x: Continuation) { - } + suspend fun suspendHere(a: Int) = 1 } fun builder(coroutine c: Controller.() -> Continuation) {} @@ -18,9 +16,8 @@ fun test() { with(A()) { suspendHere("") - // This test checks that suspending functions - // that are not from coroutine controller can't be called by suspending convention - suspendHere(1) + // With the new convention calling a suspension member with receiver different from the one obtained from the coroutine is OK + suspendHere(1) } } } diff --git a/compiler/testData/diagnostics/tests/coroutines/irrelevantSuspendDeclarations.txt b/compiler/testData/diagnostics/tests/coroutines/irrelevantSuspendDeclarations.txt index 1aee26178e3..a73c8159cd9 100644 --- a/compiler/testData/diagnostics/tests/coroutines/irrelevantSuspendDeclarations.txt +++ b/compiler/testData/diagnostics/tests/coroutines/irrelevantSuspendDeclarations.txt @@ -7,7 +7,7 @@ public final class A { public constructor A() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public final suspend fun suspendHere(/*0*/ a: kotlin.Int, /*1*/ x: kotlin.coroutines.Continuation): kotlin.Unit + public final suspend fun suspendHere(/*0*/ a: kotlin.Int): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } @@ -15,6 +15,6 @@ public final class Controller { public constructor Controller() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public final suspend fun suspendHere(/*0*/ a: kotlin.String, /*1*/ x: kotlin.coroutines.Continuation): kotlin.Unit + public final suspend fun suspendHere(/*0*/ a: kotlin.String): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/compiler/testData/diagnostics/tests/coroutines/nonLocalSuspension.kt b/compiler/testData/diagnostics/tests/coroutines/nonLocalSuspension.kt index 2a9bf2e2f64..c74cb0dd762 100644 --- a/compiler/testData/diagnostics/tests/coroutines/nonLocalSuspension.kt +++ b/compiler/testData/diagnostics/tests/coroutines/nonLocalSuspension.kt @@ -1,11 +1,9 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER class Controller { - suspend fun suspendHere(x: Continuation) { - } + suspend fun suspendHere() = 1 - suspend fun another(a: T, x: Continuation) { - } + suspend fun another(a: T) = 1 } fun builder(coroutine c: Controller.() -> Continuation) { } @@ -62,7 +60,7 @@ fun foo() { suspendHere() another(1) - another("") + another("") } } } diff --git a/compiler/testData/diagnostics/tests/coroutines/nonLocalSuspension.txt b/compiler/testData/diagnostics/tests/coroutines/nonLocalSuspension.txt index b75e8cc9a68..b0b3c0da645 100644 --- a/compiler/testData/diagnostics/tests/coroutines/nonLocalSuspension.txt +++ b/compiler/testData/diagnostics/tests/coroutines/nonLocalSuspension.txt @@ -8,9 +8,9 @@ public inline fun runCross(/*0*/ crossinline x: () -> kotlin.Unit): kotlin.Unit public final class Controller { public constructor Controller() - public final suspend fun another(/*0*/ a: T, /*1*/ x: kotlin.coroutines.Continuation): kotlin.Unit + public final suspend fun another(/*0*/ a: T): kotlin.Int public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public final suspend fun suspendHere(/*0*/ x: kotlin.coroutines.Continuation): kotlin.Unit + public final suspend fun suspendHere(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.kt b/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.kt index 0861e54a892..50d11d75c39 100644 --- a/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.kt +++ b/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.kt @@ -1,44 +1,25 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE -suspend fun notMember(x: Continuation) { +suspend fun notMember(q: Double) = 1 -} +suspend fun String.wrongExtension(x: Any) = 1 -suspend fun String.wrongExtension(x: Continuation) { -} +suspend fun Controller.controllerReceiver() = 1 -suspend fun Controller.correctExtension(x: Continuation) { -} - -@AllowSuspendExtensions class Controller { - suspend fun valid(x: Continuation) { + // is still valid + suspend fun oldConvention(x: Continuation) { } - inline suspend fun inlineFun(x: Continuation) { + suspend fun noParameters() { } - suspend fun noParams() { + suspend fun oneParameter(q: Any) {} + suspend fun varargParameter(vararg q: Any) {} + suspend fun returnsString(q: Any) = "" - } + inline suspend fun inlineFun(x: Int) {} - suspend fun wrongParam(x: Collection) { - - } - - suspend fun starProjection(x: Continuation<*>) { - - } - - suspend fun varargs(vararg x: Continuation) { - - } - - suspend fun String.memberExtension(x: Continuation) { - - } - - suspend fun returnsUnit(x: Continuation) = Unit - suspend fun returnsNotUnit(x: Continuation) = 1 + suspend fun String.memberExtension() = 1 } diff --git a/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.txt b/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.txt index 94877585f17..105425acf6e 100644 --- a/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.txt +++ b/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.txt @@ -1,21 +1,19 @@ package -public suspend fun notMember(/*0*/ x: kotlin.coroutines.Continuation): kotlin.Unit -public suspend fun Controller.correctExtension(/*0*/ x: kotlin.coroutines.Continuation): kotlin.Unit -public suspend fun kotlin.String.wrongExtension(/*0*/ x: kotlin.coroutines.Continuation): kotlin.Unit +public suspend fun notMember(/*0*/ q: kotlin.Double): kotlin.Int +public suspend fun Controller.controllerReceiver(): kotlin.Int +public suspend fun kotlin.String.wrongExtension(/*0*/ x: kotlin.Any): kotlin.Int -@kotlin.coroutines.AllowSuspendExtensions public final class Controller { +public final class Controller { public constructor Controller() public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public final inline suspend fun inlineFun(/*0*/ x: kotlin.coroutines.Continuation): kotlin.Unit - public final suspend fun noParams(): kotlin.Unit - public final suspend fun returnsNotUnit(/*0*/ x: kotlin.coroutines.Continuation): kotlin.Int - public final suspend fun returnsUnit(/*0*/ x: kotlin.coroutines.Continuation): kotlin.Unit - public final suspend fun starProjection(/*0*/ x: kotlin.coroutines.Continuation<*>): kotlin.Unit + public final inline suspend fun inlineFun(/*0*/ x: kotlin.Int): kotlin.Unit + public final suspend fun noParameters(): kotlin.Unit + public final suspend fun oldConvention(/*0*/ x: kotlin.coroutines.Continuation): kotlin.Unit + public final suspend fun oneParameter(/*0*/ q: kotlin.Any): kotlin.Unit + public final suspend fun returnsString(/*0*/ q: kotlin.Any): kotlin.String public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String - public final suspend fun valid(/*0*/ x: kotlin.coroutines.Continuation): kotlin.Unit - public final suspend fun varargs(/*0*/ vararg x: kotlin.coroutines.Continuation /*kotlin.Array>*/): kotlin.Unit - public final suspend fun wrongParam(/*0*/ x: kotlin.collections.Collection): kotlin.Unit - public final suspend fun kotlin.String.memberExtension(/*0*/ x: kotlin.coroutines.Continuation): kotlin.Unit + public final suspend fun varargParameter(/*0*/ vararg q: kotlin.Any /*kotlin.Array*/): kotlin.Unit + public final suspend fun kotlin.String.memberExtension(): kotlin.Int } diff --git a/compiler/testData/diagnostics/tests/coroutines/suspendExtensionFunctions.kt b/compiler/testData/diagnostics/tests/coroutines/suspendExtensionFunctions.kt deleted file mode 100644 index b4599c1b987..00000000000 --- a/compiler/testData/diagnostics/tests/coroutines/suspendExtensionFunctions.kt +++ /dev/null @@ -1,60 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER -// !CHECK_TYPE -@AllowSuspendExtensions -class Controller - -suspend fun Controller.noParams(c: Continuation) { - -} -suspend fun Controller.yieldString(value: String, c: Continuation) { -} - -suspend fun Controller.await(f: () -> V, machine: Continuation) { -} - -suspend fun Controller.await(f: Int, machine: Continuation) { -} - -suspend fun Controller.severalParams(x: String, y: Int, machine: Continuation) { -} - -// These two must be prohibited because String and Any are not properly annotated -suspend fun String.wrongReceiver(y: Int, machine: Continuation) { -} - -suspend fun Any.anyReceiver(y: Int, machine: Continuation) { -} - -fun builder(coroutine c: Controller.() -> Continuation) {} - -fun test() { - builder { - noParams() - yieldString("abc") checkType { _() } - yieldString(1) checkType { _() } - - await { "123" } checkType { _() } - - // Inference from lambda return type - await { 123 } checkType { _() } - - // Inference from expected type - checkSubtype(await(567)) - - await(123) checkType { _() } - - severalParams("", 89) checkType { _() } - // TODO: prohibit such calls - severalParams("", 89, 6.9) checkType { _() } - severalParams("", 89, this as Continuation) checkType { _() } - - wrongReceiver(1) - - with("") { - wrongReceiver(2) - } - - // Though such calls are allowed declarations with not-annotated receiver should be prohibited - anyReceiver(3) - } -} diff --git a/compiler/testData/diagnostics/tests/coroutines/suspendExtensionFunctions.txt b/compiler/testData/diagnostics/tests/coroutines/suspendExtensionFunctions.txt deleted file mode 100644 index 917b556fe31..00000000000 --- a/compiler/testData/diagnostics/tests/coroutines/suspendExtensionFunctions.txt +++ /dev/null @@ -1,18 +0,0 @@ -package - -public fun builder(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation): kotlin.Unit -public fun test(): kotlin.Unit -public suspend fun kotlin.Any.anyReceiver(/*0*/ y: kotlin.Int, /*1*/ machine: kotlin.coroutines.Continuation): kotlin.Unit -public suspend fun Controller.await(/*0*/ f: () -> V, /*1*/ machine: kotlin.coroutines.Continuation): kotlin.Unit -public suspend fun Controller.await(/*0*/ f: kotlin.Int, /*1*/ machine: kotlin.coroutines.Continuation): kotlin.Unit -public suspend fun Controller.noParams(/*0*/ c: kotlin.coroutines.Continuation): kotlin.Unit -public suspend fun Controller.severalParams(/*0*/ x: kotlin.String, /*1*/ y: kotlin.Int, /*2*/ machine: kotlin.coroutines.Continuation): kotlin.Unit -public suspend fun kotlin.String.wrongReceiver(/*0*/ y: kotlin.Int, /*1*/ machine: kotlin.coroutines.Continuation): kotlin.Unit -public suspend fun Controller.yieldString(/*0*/ value: kotlin.String, /*1*/ c: kotlin.coroutines.Continuation): kotlin.Unit - -@kotlin.coroutines.AllowSuspendExtensions public final class Controller { - public constructor Controller() - public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean - public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String -} diff --git a/compiler/testData/diagnostics/tests/coroutines/suspendExternalFunctions.kt b/compiler/testData/diagnostics/tests/coroutines/suspendExternalFunctions.kt new file mode 100644 index 00000000000..d16e1cd417b --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/suspendExternalFunctions.kt @@ -0,0 +1,53 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// !CHECK_TYPE +class Controller + +suspend fun noParams() { + +} + +suspend fun yieldString(value: String) {} + +suspend fun await(f: () -> V) = f() + +suspend fun Controller.await(f: Int): V = null!! + +suspend fun Controller.severalParams(x: String, y: Int) = 1.0 + +suspend fun String.stringReceiver(y: Int) = 1.0 + +suspend fun Any.anyReceiver(y: Int) = 1.0 + +fun builder(coroutine c: Controller.() -> Continuation) {} + +fun test() { + builder { + noParams() + yieldString("abc") checkType { _() } + yieldString(1) checkType { _() } + + await { "123" } checkType { _() } + + // Inference from lambda return type + await { 123 } checkType { _() } + + // Inference from expected type + checkSubtype(await(567)) + + await(123) checkType { _() } + + severalParams("", 89) checkType { _() } + // TODO: should we allow somehow to call with passing continuation explicitly? + severalParams("", 89, 6.9) checkType { _() } + severalParams("", 89, this as Continuation) checkType { _() } + + stringReceiver(1) + + with("") { + stringReceiver(2) + } + + // Though such calls are allowed declarations with not-annotated receiver should be prohibited + anyReceiver(3) + } +} diff --git a/compiler/testData/diagnostics/tests/coroutines/suspendExternalFunctions.txt b/compiler/testData/diagnostics/tests/coroutines/suspendExternalFunctions.txt new file mode 100644 index 00000000000..efdd9e78e4a --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/suspendExternalFunctions.txt @@ -0,0 +1,18 @@ +package + +public suspend fun await(/*0*/ f: () -> V): V +public fun builder(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation): kotlin.Unit +public suspend fun noParams(): kotlin.Unit +public fun test(): kotlin.Unit +public suspend fun yieldString(/*0*/ value: kotlin.String): kotlin.Unit +public suspend fun kotlin.Any.anyReceiver(/*0*/ y: kotlin.Int): kotlin.Double +public suspend fun Controller.await(/*0*/ f: kotlin.Int): V +public suspend fun Controller.severalParams(/*0*/ x: kotlin.String, /*1*/ y: kotlin.Int): kotlin.Double +public suspend fun kotlin.String.stringReceiver(/*0*/ y: kotlin.Int): kotlin.Double + +public final class Controller { + public constructor Controller() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/coroutines/suspendFunctions.kt b/compiler/testData/diagnostics/tests/coroutines/suspendFunctions.kt index 935d48bf8fd..2e3308bce6b 100644 --- a/compiler/testData/diagnostics/tests/coroutines/suspendFunctions.kt +++ b/compiler/testData/diagnostics/tests/coroutines/suspendFunctions.kt @@ -1,20 +1,16 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER // !CHECK_TYPE class Controller { - suspend fun noParams(c: Continuation) { + suspend fun noParams() { } - suspend fun yieldString(value: String, c: Continuation) { - } + suspend fun yieldString(value: String) {} - suspend fun await(f: () -> V, machine: Continuation) { - } + suspend fun await(f: () -> V): V = f() - suspend fun await(f: Int, machine: Continuation) { - } + suspend fun await(f: Int): V = null!! - suspend fun severalParams(x: String, y: Int, machine: Continuation) { - } + suspend fun severalParams(x: String, y: Int) = 1.0 } fun builder(coroutine c: Controller.() -> Continuation) {} @@ -36,8 +32,9 @@ fun test() { await(123) checkType { _() } severalParams("", 89) checkType { _() } - // TODO: prohibit such calls - severalParams("", 89, 6.9) checkType { _() } - severalParams("", 89, this as Continuation) checkType { _() } + + // TODO: should we allow somehow to call with passing continuation explicitly? + severalParams("", 89, 6.9) checkType { _() } + severalParams("", 89, this as Continuation) checkType { _() } } } diff --git a/compiler/testData/diagnostics/tests/coroutines/suspendFunctions.txt b/compiler/testData/diagnostics/tests/coroutines/suspendFunctions.txt index ed747e9ceb4..6ef1fac496f 100644 --- a/compiler/testData/diagnostics/tests/coroutines/suspendFunctions.txt +++ b/compiler/testData/diagnostics/tests/coroutines/suspendFunctions.txt @@ -5,12 +5,12 @@ public fun test(): kotlin.Unit public final class Controller { public constructor Controller() - public final suspend fun await(/*0*/ f: () -> V, /*1*/ machine: kotlin.coroutines.Continuation): kotlin.Unit - public final suspend fun await(/*0*/ f: kotlin.Int, /*1*/ machine: kotlin.coroutines.Continuation): kotlin.Unit + public final suspend fun await(/*0*/ f: () -> V): V + public final suspend fun await(/*0*/ f: kotlin.Int): V public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int - public final suspend fun noParams(/*0*/ c: kotlin.coroutines.Continuation): kotlin.Unit - public final suspend fun severalParams(/*0*/ x: kotlin.String, /*1*/ y: kotlin.Int, /*2*/ machine: kotlin.coroutines.Continuation): kotlin.Unit + public final suspend fun noParams(): kotlin.Unit + public final suspend fun severalParams(/*0*/ x: kotlin.String, /*1*/ y: kotlin.Int): kotlin.Double public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String - public final suspend fun yieldString(/*0*/ value: kotlin.String, /*1*/ c: kotlin.coroutines.Continuation): kotlin.Unit + public final suspend fun yieldString(/*0*/ value: kotlin.String): kotlin.Unit } diff --git a/compiler/testData/diagnostics/tests/coroutines/tryCatchLambda.kt b/compiler/testData/diagnostics/tests/coroutines/tryCatchLambda.kt index 4914f145f3a..eb216b2e8f8 100644 --- a/compiler/testData/diagnostics/tests/coroutines/tryCatchLambda.kt +++ b/compiler/testData/diagnostics/tests/coroutines/tryCatchLambda.kt @@ -1,7 +1,7 @@ // !DIAGNOSTICS: -UNUSED_PARAMETER -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE -UNUSED_VARIABLE class GenericController { operator fun handleResult(x: T, c: Continuation) { } - suspend fun await(f: V, machine: Continuation) {} + suspend fun await(f: V): V = f } fun genericBuilder(coroutine c: GenericController.() -> Continuation): T = null!! diff --git a/compiler/testData/diagnostics/tests/coroutines/tryCatchLambda.txt b/compiler/testData/diagnostics/tests/coroutines/tryCatchLambda.txt index 42d02b66f14..ba6251b4693 100644 --- a/compiler/testData/diagnostics/tests/coroutines/tryCatchLambda.txt +++ b/compiler/testData/diagnostics/tests/coroutines/tryCatchLambda.txt @@ -5,7 +5,7 @@ public fun genericBuilder(/*0*/ coroutine c: GenericController.() - public final class GenericController { public constructor GenericController() - public final suspend fun await(/*0*/ f: V, /*1*/ machine: kotlin.coroutines.Continuation): kotlin.Unit + public final suspend fun await(/*0*/ f: V): V public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public final operator fun handleResult(/*0*/ x: T, /*1*/ c: kotlin.coroutines.Continuation): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/coroutines/unsupported.kt b/compiler/testData/diagnostics/tests/coroutines/unsupported.kt index 7fed9eb466e..ff995bd77b7 100644 --- a/compiler/testData/diagnostics/tests/coroutines/unsupported.kt +++ b/compiler/testData/diagnostics/tests/coroutines/unsupported.kt @@ -2,9 +2,7 @@ // !LANGUAGE: -Coroutines class Controller { - suspend fun suspendHere(x: Continuation) { - x.resume("OK") - } + suspend fun suspendHere(): String = "OK" operator fun handleResult(x: String, y: Continuation) {} diff --git a/compiler/testData/diagnostics/tests/coroutines/unsupported.txt b/compiler/testData/diagnostics/tests/coroutines/unsupported.txt index f45292aa51d..0c1d47c74dc 100644 --- a/compiler/testData/diagnostics/tests/coroutines/unsupported.txt +++ b/compiler/testData/diagnostics/tests/coroutines/unsupported.txt @@ -10,6 +10,6 @@ public final class Controller { public final operator fun handleResult(/*0*/ x: kotlin.String, /*1*/ y: kotlin.coroutines.Continuation): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public final operator fun interceptResume(/*0*/ x: () -> kotlin.Unit): kotlin.Unit - public final suspend fun suspendHere(/*0*/ x: kotlin.coroutines.Continuation): kotlin.Unit + public final suspend fun suspendHere(): kotlin.String public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String } diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 175c11fd2b1..096e6c28165 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -4288,9 +4288,9 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } - @TestMetadata("suspendExtensionFunctions.kt") - public void testSuspendExtensionFunctions() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/suspendExtensionFunctions.kt"); + @TestMetadata("suspendExternalFunctions.kt") + public void testSuspendExternalFunctions() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/suspendExternalFunctions.kt"); doTest(fileName); } diff --git a/idea/testData/checker/infos/suspendApplicability.kt b/idea/testData/checker/infos/suspendApplicability.kt deleted file mode 100644 index 987145420cf..00000000000 --- a/idea/testData/checker/infos/suspendApplicability.kt +++ /dev/null @@ -1,43 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE -suspend fun notMember(x: Continuation) { - -} - -suspend fun String.wrongExtension(x: Continuation) { -} - -suspend fun Controller.correctExtension(x: Continuation) { -} - -@AllowSuspendExtensions -class Controller { - suspend fun valid(x: Continuation) { - - } - - inline suspend fun inlineFun(x: Continuation) { - - } - - suspend fun noParams() { - - } - - suspend fun wrongParam(x: Collection) { - - } - - suspend fun starProjection(x: Continuation<*>) { - - } - - suspend fun varargs(vararg x: Continuation) { - - } - - suspend fun String.memberExtension(x: Continuation) { - - } - - suspend fun returnsNotUnit(x: Continuation) = 1 -} diff --git a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java b/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java index f56c9b9dc09..006f55e8cc3 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java @@ -935,12 +935,6 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { doTestWithInfos(fileName); } - @TestMetadata("suspendApplicability.kt") - public void testSuspendApplicability() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/suspendApplicability.kt"); - doTestWithInfos(fileName); - } - @TestMetadata("threeImplicitReceivers.kt") public void testThreeImplicitReceivers() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/threeImplicitReceivers.kt");