diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OperatorModifierChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OperatorModifierChecker.kt index 0b4f291e060..f1e09945b80 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OperatorModifierChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OperatorModifierChecker.kt @@ -71,4 +71,7 @@ object OperatorModifierChecker { } private val COROUTINE_OPERATOR_NAMES = - setOf(OperatorNameConventions.COROUTINE_HANDLE_RESULT, OperatorNameConventions.COROUTINE_HANDLE_EXCEPTION) + setOf(OperatorNameConventions.COROUTINE_HANDLE_RESULT, + OperatorNameConventions.COROUTINE_HANDLE_EXCEPTION, + OperatorNameConventions.COROUTINE_INTERCEPT_RESUME + ) diff --git a/compiler/testData/diagnostics/tests/coroutines/interceptResume.kt b/compiler/testData/diagnostics/tests/coroutines/interceptResume.kt new file mode 100644 index 00000000000..7f4436cd975 --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/interceptResume.kt @@ -0,0 +1,38 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +class A1 { + operator fun interceptResume(x: () -> Unit) {} +} + +operator fun A1.interceptResume(x: () -> Unit) {} + +class A2 { + operator fun interceptResume(x: () -> Unit, w: Int) {} +} + +class A3 { + operator fun interceptResume(x: String.() -> Unit) = 1 +} + +class A4 { + operator fun interceptResume(x: (String) -> Unit) {} +} + +class A5 { + operator fun interceptResume(x: () -> Int) {} +} + +class A6 { + operator fun interceptResume(x: () -> Unit) {} +} + +class A7 { + operator fun interceptResume(x: () -> Unit = {}) {} +} + +class A8 { + operator fun interceptResume(vararg x: () -> Unit) {} +} + +class A9 { + inline operator fun interceptResume(x: () -> Unit) {} +} diff --git a/compiler/testData/diagnostics/tests/coroutines/interceptResume.txt b/compiler/testData/diagnostics/tests/coroutines/interceptResume.txt new file mode 100644 index 00000000000..1e44fc6134e --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/interceptResume.txt @@ -0,0 +1,75 @@ +package + +public operator fun A1.interceptResume(/*0*/ x: () -> kotlin.Unit): kotlin.Unit + +public final class A1 { + public constructor A1() + 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 operator fun interceptResume(/*0*/ x: () -> kotlin.Unit): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class A2 { + public constructor A2() + 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 operator fun interceptResume(/*0*/ x: () -> kotlin.Unit, /*1*/ w: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class A3 { + public constructor A3() + 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 operator fun interceptResume(/*0*/ x: kotlin.String.() -> kotlin.Unit): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class A4 { + public constructor A4() + 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 operator fun interceptResume(/*0*/ x: (kotlin.String) -> kotlin.Unit): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class A5 { + public constructor A5() + 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 operator fun interceptResume(/*0*/ x: () -> kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class A6 { + public constructor A6() + 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 operator fun interceptResume(/*0*/ x: () -> kotlin.Unit): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class A7 { + public constructor A7() + 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 operator fun interceptResume(/*0*/ x: () -> kotlin.Unit = ...): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class A8 { + public constructor A8() + 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 operator fun interceptResume(/*0*/ vararg x: () -> kotlin.Unit /*kotlin.Array kotlin.Unit>*/): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class A9 { + public constructor A9() + 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 operator inline fun interceptResume(/*0*/ x: () -> kotlin.Unit): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/testData/diagnostics/tests/coroutines/unsupported.kt b/compiler/testData/diagnostics/tests/coroutines/unsupported.kt index 0e4837f0cb6..7fed9eb466e 100644 --- a/compiler/testData/diagnostics/tests/coroutines/unsupported.kt +++ b/compiler/testData/diagnostics/tests/coroutines/unsupported.kt @@ -10,6 +10,9 @@ class Controller { operator fun handleException(x: Throwable, y: Continuation) { } + + operator fun interceptResume(x: () -> Unit) { + } } fun builder(coroutine c: Controller.() -> Continuation) { diff --git a/compiler/testData/diagnostics/tests/coroutines/unsupported.txt b/compiler/testData/diagnostics/tests/coroutines/unsupported.txt index 15887f61bca..f45292aa51d 100644 --- a/compiler/testData/diagnostics/tests/coroutines/unsupported.txt +++ b/compiler/testData/diagnostics/tests/coroutines/unsupported.txt @@ -9,6 +9,7 @@ public final class Controller { public final operator fun handleException(/*0*/ x: kotlin.Throwable, /*1*/ y: kotlin.coroutines.Continuation): kotlin.Unit 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 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 9ce90279065..ca6c543b4c8 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -4234,6 +4234,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("interceptResume.kt") + public void testInterceptResume() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/interceptResume.kt"); + doTest(fileName); + } + @TestMetadata("irrelevantSuspendDeclarations.kt") public void testIrrelevantSuspendDeclarations() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/irrelevantSuspendDeclarations.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/util/OperatorNameConventions.kt b/core/descriptors/src/org/jetbrains/kotlin/util/OperatorNameConventions.kt index 9be51504707..6ab1c370273 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/util/OperatorNameConventions.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/util/OperatorNameConventions.kt @@ -58,6 +58,8 @@ object OperatorNameConventions { @JvmField val MINUS_ASSIGN = Name.identifier("minusAssign") @JvmField val COROUTINE_HANDLE_RESULT = Name.identifier("handleResult") @JvmField val COROUTINE_HANDLE_EXCEPTION = Name.identifier("handleException") + @JvmField val COROUTINE_INTERCEPT_RESUME = Name.identifier("interceptResume") + @JvmField val PROPERTY_DELEGATED = Name.identifier("propertyDelegated") diff --git a/core/descriptors/src/org/jetbrains/kotlin/util/modifierChecks.kt b/core/descriptors/src/org/jetbrains/kotlin/util/modifierChecks.kt index 446d7e57e00..d3c22ae6178 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/util/modifierChecks.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/util/modifierChecks.kt @@ -16,8 +16,7 @@ package org.jetbrains.kotlin.util -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.builtins.ReflectionTypes +import org.jetbrains.kotlin.builtins.* import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor @@ -37,6 +36,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions.COMPONENT_REGEX import org.jetbrains.kotlin.util.OperatorNameConventions.CONTAINS import org.jetbrains.kotlin.util.OperatorNameConventions.COROUTINE_HANDLE_EXCEPTION import org.jetbrains.kotlin.util.OperatorNameConventions.COROUTINE_HANDLE_RESULT +import org.jetbrains.kotlin.util.OperatorNameConventions.COROUTINE_INTERCEPT_RESUME import org.jetbrains.kotlin.util.OperatorNameConventions.DEC import org.jetbrains.kotlin.util.OperatorNameConventions.EQUALS import org.jetbrains.kotlin.util.OperatorNameConventions.GET @@ -163,7 +163,7 @@ internal class Checks private constructor( abstract class AbstractModifierChecks { abstract internal val checks: List - + inline fun ensure(cond: Boolean, msg: () -> String) = if (!cond) msg() else null fun check(functionDescriptor: FunctionDescriptor): CheckResult { @@ -217,6 +217,14 @@ object OperatorChecks : AbstractModifierChecks() { "First parameter should be 'Throwable'" } }, + Checks(COROUTINE_INTERCEPT_RESUME, Member, ValueParameterCountCheck.Equals(1), ReturnsUnit, NoDefaultAndVarargsCheck, + NoTypeParametersCheck + ) { + val parameterType = valueParameters.single().type + ensure(parameterType.isNonExtensionFunctionType && parameterType.getValueParameterTypesFromFunctionType().isEmpty() && + parameterType.getReturnTypeFromFunctionType().isUnit() + ) { "Value parameter must have a functional type '() -> Unit'" } + }, Checks(PROPERTY_DELEGATED, Member, ValueParameterCountCheck.Equals(1)) //TODO: more checks required! ) @@ -236,4 +244,4 @@ object InfixChecks : AbstractModifierChecks() { Checks(MemberKindCheck.MemberOrExtension, SingleValueParameter, NoDefaultAndVarargsCheck)) } -fun FunctionDescriptor.isValidOperator() = isOperator && OperatorChecks.check(this).isSuccess \ No newline at end of file +fun FunctionDescriptor.isValidOperator() = isOperator && OperatorChecks.check(this).isSuccess