diff --git a/compiler/frontend/src/org/jetbrains/kotlin/coroutines/coroutineUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/coroutines/coroutineUtil.kt index 798e1ea994e..3501b4b5a11 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/coroutines/coroutineUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/coroutines/coroutineUtil.kt @@ -18,14 +18,17 @@ package org.jetbrains.kotlin.coroutines import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.TemporaryBindingTrace import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils import org.jetbrains.kotlin.types.expressions.FakeCallKind @@ -77,10 +80,13 @@ fun FakeCallResolver.resolveCoroutineHandleResultCallIfNeeded( val resolutionResults = resolveFakeCall( context.replaceBindingTrace(temporaryBindingTrace), functionDescriptor.extensionReceiverParameter!!.value, - Name.identifier("handleResult"), callElement, callElement, FakeCallKind.OTHER, + OperatorNameConventions.COROUTINE_HANDLE_RESULT, callElement, callElement, FakeCallKind.OTHER, listOf(firstArgument, continuation)) if (resolutionResults.isSuccess) { context.trace.record(BindingContext.RETURN_HANDLE_RESULT_RESOLVED_CALL, callElement, resolutionResults.resultingCall) } } + +fun KotlinType.isValidContinuation() = + (constructor.declarationDescriptor as? ClassDescriptor)?.fqNameUnsafe == DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME.toUnsafe() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 82e2a33c92b..bc97d6a4265 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -622,6 +622,8 @@ public interface Errors { DiagnosticFactory2 OPERATOR_MODIFIER_REQUIRED = DiagnosticFactory2.create(ERROR); DiagnosticFactory2 INFIX_MODIFIER_REQUIRED = DiagnosticFactory2.create(ERROR); + DiagnosticFactory2 INAPPLICABLE_MODIFIER = DiagnosticFactory2.create(ERROR); + // Labels DiagnosticFactory0 LABEL_NAME_CLASH = DiagnosticFactory0.create(WARNING); 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 1b0faf91557..079915321b7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -383,6 +383,8 @@ public class DefaultErrorMessages { MAP.put(OPERATOR_MODIFIER_REQUIRED, "''operator'' modifier is required on ''{0}'' in ''{1}''", NAME, STRING); MAP.put(INFIX_MODIFIER_REQUIRED, "''infix'' modifier is required on ''{0}'' in ''{1}''", NAME, STRING); + MAP.put(INAPPLICABLE_MODIFIER, "''{0}'' modifier is inapplicable. The reason is that {1}", TO_STRING, STRING); + MAP.put(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY, "Returns are not allowed for functions with expression body. Use block body in '{...}'"); MAP.put(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY, "A 'return' expression required in a function with a block body ('{...}')"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt index 37edcac40f8..2ed1301dc32 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt @@ -81,7 +81,7 @@ object ModifierCheckerCore { NOINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER), COROUTINE_KEYWORD to EnumSet.of(VALUE_PARAMETER), TAILREC_KEYWORD to EnumSet.of(FUNCTION), - SUSPEND_KEYWORD to EnumSet.of(FUNCTION), + SUSPEND_KEYWORD to EnumSet.of(MEMBER_FUNCTION), EXTERNAL_KEYWORD to EnumSet.of(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER), ANNOTATION_KEYWORD to EnumSet.of(ANNOTATION_CLASS), CROSSINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER), diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/SuspendModifierChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/SuspendModifierChecker.kt new file mode 100644 index 00000000000..437d6f35ae7 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/SuspendModifierChecker.kt @@ -0,0 +1,113 @@ +/* + * 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 + +import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType +import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType +import org.jetbrains.kotlin.builtins.isExtensionFunctionType +import org.jetbrains.kotlin.coroutines.isValidContinuation +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.incremental.KotlinLookupLocation +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtDeclarationWithBody +import org.jetbrains.kotlin.psi.KtFunction +import org.jetbrains.kotlin.types.typeUtil.isUnit +import org.jetbrains.kotlin.util.OperatorNameConventions +import org.jetbrains.kotlin.utils.sure + +object SuspendModifierChecker : DeclarationChecker { + 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.isInline) { + report("inline suspend functions are not supported") + return + } + + val isValidContinuation = functionDescriptor.valueParameters.lastOrNull()?.type?.isValidContinuation() ?: false + if (!isValidContinuation) { + report("last parameter of suspend function should have a type of Continuation") + return + } + } +} + +object CoroutineModifierChecker : DeclarationChecker { + override fun check( + declaration: KtDeclaration, + descriptor: DeclarationDescriptor, + diagnosticHolder: DiagnosticSink, + bindingContext: BindingContext + ) { + val functionDescriptor = descriptor as? FunctionDescriptor ?: return + if (declaration !is KtDeclarationWithBody) return + val location = KotlinLookupLocation(declaration) + + for ((parameterDescriptor, parameterDeclaration) in functionDescriptor.valueParameters.zip(declaration.valueParameters)) { + if (!parameterDescriptor.isCoroutine) continue + val coroutineModifier = parameterDeclaration.modifierList?.getModifier(KtTokens.COROUTINE_KEYWORD) ?: continue + + fun report(message: String) { + diagnosticHolder.report(Errors.INAPPLICABLE_MODIFIER.on(coroutineModifier, KtTokens.COROUTINE_KEYWORD, message)) + } + + if (!parameterDescriptor.type.isExtensionFunctionType) { + report("parameter should have function type with extension like 'Controller.() -> Continuation'") + continue + } + + val returnType = getReturnTypeFromFunctionType(parameterDescriptor.type) + + if (returnType.isMarkedNullable || !returnType.isValidContinuation() || !returnType.arguments.single().type.isUnit()) { + report("parameter should have function type like 'Controller.() -> Continuation' (Continuation for return type is necessary)") + continue + } + + if (functionDescriptor.isInline && !parameterDescriptor.isNoinline) { + report("coroutine parameter of inline function should be marked as 'noinline'") + continue + } + + val controller = getReceiverTypeFromFunctionType(parameterDescriptor.type)!! + + val handleResultFunctions = + controller.memberScope + .getContributedFunctions(OperatorNameConventions.COROUTINE_HANDLE_RESULT, location) + .filter { it.isOperator } + + if (handleResultFunctions.size > 1) { + report("only one operator handleResult should be declared for controller, but ${handleResultFunctions.size} found") + continue + } + } + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index 3db024e8645..97438985760 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -63,7 +63,9 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf( UnderscoreChecker, InlineParameterChecker, OperatorModifierChecker(), - InfixModifierChecker()) + InfixModifierChecker(), + SuspendModifierChecker, + CoroutineModifierChecker) private val DEFAULT_CALL_CHECKERS = listOf(CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker(), SafeCallChecker(), InvokeConventionChecker(), CallReturnsArrayOfNothingChecker(), diff --git a/compiler/testData/diagnostics/tests/coroutines/coroutineApplicability.kt b/compiler/testData/diagnostics/tests/coroutines/coroutineApplicability.kt new file mode 100644 index 00000000000..f58465c39ad --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/coroutineApplicability.kt @@ -0,0 +1,45 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE +class Controller + +class A(coroutine c: Controller.() -> Continuation, y: Int) { + var x: String = "" + set(coroutine x) { + + } + + constructor(coroutine c: Controller.() -> Continuation) : this(c, 1) + constructor(coroutine c: Controller.() -> Continuation, y: String) : this(c, 2) +} + +fun valid(coroutine c: Controller.() -> Continuation) { + +} + +fun noFunctionType(coroutine c: Unit) { + +} + +fun noExtensionFunction(coroutine c: (Controller) -> Continuation) { + +} + +fun nullableReturnType(coroutine c: Controller.() -> Continuation?) { + +} + +fun wrongReturnType(coroutine c: Controller.() -> Collection) { + +} + +fun notUnitContinuation(coroutine c: Controller.() -> Continuation) { + +} + +inline fun inlineBuilder(coroutine c: Controller.() -> Continuation) { + +} + +inline fun inlineBuilderNoInlineCoroutine(coroutine noinline c: Controller.() -> Continuation) { + +} + diff --git a/compiler/testData/diagnostics/tests/coroutines/coroutineApplicability.txt b/compiler/testData/diagnostics/tests/coroutines/coroutineApplicability.txt new file mode 100644 index 00000000000..1ed759a2876 --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/coroutineApplicability.txt @@ -0,0 +1,27 @@ +package + +public inline fun inlineBuilder(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation): kotlin.Unit +public inline fun inlineBuilderNoInlineCoroutine(/*0*/ noinline coroutine c: Controller.() -> kotlin.coroutines.Continuation): kotlin.Unit +public fun noExtensionFunction(/*0*/ coroutine c: (Controller) -> kotlin.coroutines.Continuation): kotlin.Unit +public fun noFunctionType(/*0*/ coroutine c: kotlin.Unit): kotlin.Unit +public fun notUnitContinuation(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation): kotlin.Unit +public fun nullableReturnType(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation?): kotlin.Unit +public fun valid(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation): kotlin.Unit +public fun wrongReturnType(/*0*/ coroutine c: Controller.() -> kotlin.collections.Collection): kotlin.Unit + +public final class A { + public constructor A(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation, /*1*/ y: kotlin.String) + public constructor A(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation) + public constructor A(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation, /*1*/ y: kotlin.Int) + public final var x: kotlin.String + 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 +} + +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/lambdaExpectedType.kt b/compiler/testData/diagnostics/tests/coroutines/lambdaExpectedType.kt index 2fd72507c20..1b9d8e822a0 100644 --- a/compiler/testData/diagnostics/tests/coroutines/lambdaExpectedType.kt +++ b/compiler/testData/diagnostics/tests/coroutines/lambdaExpectedType.kt @@ -22,7 +22,7 @@ fun emptyBuilder(coroutine c: EmptyController.() -> Continuation) = 1 fun manyArgumentsBuilder( coroutine c1: UnitController.() -> Continuation, coroutine c2: GenericController.() -> Continuation, - coroutine c3: IntController.() -> Continuation + coroutine c3: IntController.() -> Continuation ):T = null!! fun severalParamsInLambda(coroutine c: UnitController.(String, Int) -> Continuation) {} diff --git a/compiler/testData/diagnostics/tests/coroutines/lambdaExpectedType.txt b/compiler/testData/diagnostics/tests/coroutines/lambdaExpectedType.txt index c1fe5f89928..ac2d23af46a 100644 --- a/compiler/testData/diagnostics/tests/coroutines/lambdaExpectedType.txt +++ b/compiler/testData/diagnostics/tests/coroutines/lambdaExpectedType.txt @@ -4,7 +4,7 @@ public fun builder(/*0*/ coroutine c: IntController.() -> kotlin.coroutines.Cont public fun emptyBuilder(/*0*/ coroutine c: EmptyController.() -> kotlin.coroutines.Continuation): kotlin.Int public fun foo(): kotlin.Unit public fun genericBuilder(/*0*/ coroutine c: GenericController.() -> kotlin.coroutines.Continuation): T -public fun manyArgumentsBuilder(/*0*/ coroutine c1: UnitController.() -> kotlin.coroutines.Continuation, /*1*/ coroutine c2: GenericController.() -> kotlin.coroutines.Continuation, /*2*/ coroutine c3: IntController.() -> kotlin.coroutines.Continuation): T +public fun manyArgumentsBuilder(/*0*/ coroutine c1: UnitController.() -> kotlin.coroutines.Continuation, /*1*/ coroutine c2: GenericController.() -> kotlin.coroutines.Continuation, /*2*/ coroutine c3: IntController.() -> kotlin.coroutines.Continuation): T public fun severalParamsInLambda(/*0*/ coroutine c: UnitController.(kotlin.String, kotlin.Int) -> kotlin.coroutines.Continuation): kotlin.Unit public fun unitBuilder(/*0*/ coroutine c: UnitController.() -> kotlin.coroutines.Continuation): kotlin.Int diff --git a/compiler/testData/diagnostics/tests/coroutines/manyHandleResults.kt b/compiler/testData/diagnostics/tests/coroutines/manyHandleResults.kt new file mode 100644 index 00000000000..20c9c5afe08 --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/manyHandleResults.kt @@ -0,0 +1,16 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +interface A { + operator fun handleResult(x: Int, y: Continuation) {} +} + +interface B { + operator fun handleResult(x: String, y: Continuation) {} +} + +class C : A, B { + // multiple handleResults +} + +fun builder1(coroutine c: A.() -> Continuation) {} +fun builder2(coroutine c: B.() -> Continuation) {} +fun builder3(coroutine c: C.() -> Continuation) {} diff --git a/compiler/testData/diagnostics/tests/coroutines/manyHandleResults.txt b/compiler/testData/diagnostics/tests/coroutines/manyHandleResults.txt new file mode 100644 index 00000000000..7f706e2d054 --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/manyHandleResults.txt @@ -0,0 +1,28 @@ +package + +public fun builder1(/*0*/ coroutine c: A.() -> kotlin.coroutines.Continuation): kotlin.Unit +public fun builder2(/*0*/ coroutine c: B.() -> kotlin.coroutines.Continuation): kotlin.Unit +public fun builder3(/*0*/ coroutine c: C.() -> kotlin.coroutines.Continuation): kotlin.Unit + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open operator fun handleResult(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.coroutines.Continuation): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface B { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open 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 open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class C : A, B { + public constructor C() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun handleResult(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.coroutines.Continuation): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun handleResult(/*0*/ x: kotlin.String, /*1*/ y: kotlin.coroutines.Continuation): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.kt b/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.kt new file mode 100644 index 00000000000..1f424d2f039 --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.kt @@ -0,0 +1,26 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE +suspend fun notMember(x: Continuation) { + +} + +class Controller { + suspend fun valid(x: Continuation) { + + } + + inline suspend fun inlineFun(x: Continuation) { + + } + + suspend fun noParams() { + + } + + suspend fun wrongParam(x: Collection) { + + } + + suspend fun starProjection(vararg x: Continuation) { + + } +} diff --git a/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.txt b/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.txt new file mode 100644 index 00000000000..ace21376544 --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/suspendApplicability.txt @@ -0,0 +1,15 @@ +package + +public suspend fun notMember(/*0*/ x: kotlin.coroutines.Continuation): kotlin.Unit + +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 starProjection(/*0*/ vararg x: kotlin.coroutines.Continuation /*kotlin.Array>*/): kotlin.Unit + 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 wrongParam(/*0*/ x: kotlin.collections.Collection): kotlin.Unit +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 5b378e4c60f..8b43c9b8bce 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -3867,6 +3867,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("coroutineApplicability.kt") + public void testCoroutineApplicability() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/coroutineApplicability.kt"); + doTest(fileName); + } + @TestMetadata("irrelevantSuspendDeclarations.kt") public void testIrrelevantSuspendDeclarations() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/irrelevantSuspendDeclarations.kt"); @@ -3879,12 +3885,24 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("manyHandleResults.kt") + public void testManyHandleResults() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/manyHandleResults.kt"); + doTest(fileName); + } + @TestMetadata("nonLocalSuspension.kt") public void testNonLocalSuspension() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/nonLocalSuspension.kt"); doTest(fileName); } + @TestMetadata("suspendApplicability.kt") + public void testSuspendApplicability() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/suspendApplicability.kt"); + doTest(fileName); + } + @TestMetadata("suspendFunctions.kt") public void testSuspendFunctions() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/suspendFunctions.kt"); diff --git a/idea/idea-completion/testData/keywords/AfterClasses.kt b/idea/idea-completion/testData/keywords/AfterClasses.kt index 101ee4cc54d..6b906e958da 100644 --- a/idea/idea-completion/testData/keywords/AfterClasses.kt +++ b/idea/idea-completion/testData/keywords/AfterClasses.kt @@ -34,5 +34,4 @@ class B { // EXIST: external // EXIST: annotation class // EXIST: const -// EXIST: suspend // NOTHING_ELSE diff --git a/idea/idea-completion/testData/keywords/GlobalPropertyAccessors.kt b/idea/idea-completion/testData/keywords/GlobalPropertyAccessors.kt index 4b142976f63..1c3a43e3ba2 100644 --- a/idea/idea-completion/testData/keywords/GlobalPropertyAccessors.kt +++ b/idea/idea-completion/testData/keywords/GlobalPropertyAccessors.kt @@ -38,5 +38,4 @@ var a : Int // EXIST: external // EXIST: annotation class // EXIST: const -// EXIST: suspend // NOTHING_ELSE diff --git a/idea/idea-completion/testData/keywords/InTopScopeAfterPackage.kt b/idea/idea-completion/testData/keywords/InTopScopeAfterPackage.kt index 089af7852b7..a586b395277 100644 --- a/idea/idea-completion/testData/keywords/InTopScopeAfterPackage.kt +++ b/idea/idea-completion/testData/keywords/InTopScopeAfterPackage.kt @@ -25,5 +25,4 @@ package Test // EXIST: external // EXIST: annotation class // EXIST: const -// EXIST: suspend // NOTHING_ELSE diff --git a/idea/idea-completion/testData/keywords/TopScope.kt b/idea/idea-completion/testData/keywords/TopScope.kt index ee53e3ce4f4..0881897ad95 100644 --- a/idea/idea-completion/testData/keywords/TopScope.kt +++ b/idea/idea-completion/testData/keywords/TopScope.kt @@ -24,5 +24,4 @@ // EXIST: external // EXIST: annotation class // EXIST: const -// EXIST: suspend // NOTHING_ELSE diff --git a/idea/testData/checker/infos/coroutineApplicability.kt b/idea/testData/checker/infos/coroutineApplicability.kt new file mode 100644 index 00000000000..9d0d9e8d897 --- /dev/null +++ b/idea/testData/checker/infos/coroutineApplicability.kt @@ -0,0 +1,34 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE +class Controller + +fun valid(coroutine c: Controller.() -> Continuation) { + +} + +fun noFunctionType(coroutine c: Unit) { + +} + +fun noExtensionFunction(coroutine c: (Controller) -> Continuation) { + +} + +fun nullableReturnType(coroutine c: Controller.() -> Continuation?) { + +} + +fun wrongReturnType(coroutine c: Controller.() -> Collection) { + +} + +fun notUnitContinuation(coroutine c: Controller.() -> Continuation) { + +} + +inline fun inlineBuilder(coroutine c: Controller.() -> Continuation) { + +} + +inline fun inlineBuilderNoInlineCoroutine(coroutine noinline c: Controller.() -> Continuation) { + +} diff --git a/idea/testData/checker/infos/suspendApplicability.kt b/idea/testData/checker/infos/suspendApplicability.kt new file mode 100644 index 00000000000..114dde4c4f4 --- /dev/null +++ b/idea/testData/checker/infos/suspendApplicability.kt @@ -0,0 +1,26 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE +suspend fun notMember(x: Continuation) { + +} + +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<*>) { + + } +} diff --git a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java b/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java index a732ed756c4..fb27de501d3 100644 --- a/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/checkers/PsiCheckerTestGenerated.java @@ -874,6 +874,12 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest { doTestWithInfos(fileName); } + @TestMetadata("coroutineApplicability.kt") + public void testCoroutineApplicability() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/coroutineApplicability.kt"); + doTestWithInfos(fileName); + } + @TestMetadata("PropertiesWithBackingFields.kt") public void testPropertiesWithBackingFields() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/PropertiesWithBackingFields.kt"); @@ -910,6 +916,12 @@ 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("Typos.kt") public void testTypos() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/Typos.kt");