diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index 923f29bafdb..9d6e54b7236 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -84,7 +84,8 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf( ReifiedTypeParameterAnnotationChecker(), DynamicReceiverChecker, DelegationChecker(), - KClassWithIncorrectTypeArgumentChecker + KClassWithIncorrectTypeArgumentChecker, + SuspendOperatorsCheckers ) private val DEFAULT_CALL_CHECKERS = listOf( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/SuspendOperatorsCheckers.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/SuspendOperatorsCheckers.kt new file mode 100644 index 00000000000..c5eedb4c777 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/SuspendOperatorsCheckers.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2017 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.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.psi.KtDeclaration +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.util.OperatorNameConventions + +object SuspendOperatorsCheckers : SimpleDeclarationChecker { + private val UNSUPPORTED_OPERATOR_NAMES = setOf( + OperatorNameConventions.CONTAINS, + OperatorNameConventions.GET, OperatorNameConventions.SET + ) + + override fun check( + declaration: KtDeclaration, + descriptor: DeclarationDescriptor, + diagnosticHolder: DiagnosticSink, + bindingContext: BindingContext + ) { + if (descriptor is FunctionDescriptor && descriptor.isSuspend && descriptor.isOperator && + descriptor.name in UNSUPPORTED_OPERATOR_NAMES) { + declaration.modifierList?.getModifier(KtTokens.OPERATOR_KEYWORD)?.let { + diagnosticHolder.report(Errors.UNSUPPORTED.on(it, "suspend operator \"${descriptor.name}\"")) + } + } + } +} diff --git a/compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/operators.kt b/compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/operators.kt index 75130f4da20..b09942baf2e 100644 --- a/compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/operators.kt +++ b/compiler/testData/codegen/box/coroutines/suspendFunctionAsCoroutine/operators.kt @@ -44,6 +44,16 @@ class A(val x: String) { x.resume(Unit) COROUTINE_SUSPENDED } +// See KT-16221 +// operator suspend fun contains(y: String): Boolean = suspendCoroutineOrReturn { x -> +// x.resume(y == "56") +// COROUTINE_SUSPENDED +// } + + operator suspend fun compareTo(y: String): Int = suspendCoroutineOrReturn { x -> + x.resume("56".compareTo(y)) + COROUTINE_SUSPENDED + } } fun builder(c: suspend () -> Unit) { @@ -94,6 +104,22 @@ suspend fun foo7() { if (!y.isIncCalled) throw RuntimeException("fail 8") } +//suspend fun foo8() { +// if ("1" in a) throw RuntimeException("fail 9") +// if (!("1" !in a)) throw RuntimeException("fail 9") +// +// if ("56" in a) throw RuntimeException("fail 10") +// if (!("56" !in a)) throw RuntimeException("fail 11") +//} + +suspend fun checkCompareTo(v: String) = (a < v) == ("56" < v) + +suspend fun foo9() { + if (!checkCompareTo("55")) throw RuntimeException("fail 12") + if (!checkCompareTo("56")) throw RuntimeException("fail 13") + if (!checkCompareTo("57")) throw RuntimeException("fail 14") +} + fun box(): String { builder { @@ -104,6 +130,8 @@ fun box(): String { //foo5() foo6() foo7() + //foo8() + foo9() } return "OK" diff --git a/compiler/testData/codegen/light-analysis/coroutines/suspendFunctionAsCoroutine/operators.txt b/compiler/testData/codegen/light-analysis/coroutines/suspendFunctionAsCoroutine/operators.txt index d321bbe16b2..43b342a9e6f 100644 --- a/compiler/testData/codegen/light-analysis/coroutines/suspendFunctionAsCoroutine/operators.txt +++ b/compiler/testData/codegen/light-analysis/coroutines/suspendFunctionAsCoroutine/operators.txt @@ -6,6 +6,7 @@ public final class A { private field isSetValueCalled: boolean private final @org.jetbrains.annotations.NotNull field x: java.lang.String public method (@org.jetbrains.annotations.NotNull p0: java.lang.String): void + public final @org.jetbrains.annotations.Nullable method compareTo(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public final @org.jetbrains.annotations.Nullable method component1(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object public final @org.jetbrains.annotations.Nullable method getValue(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.reflect.KProperty, @org.jetbrains.annotations.NotNull p2: kotlin.coroutines.experimental.Continuation): java.lang.Object public final @org.jetbrains.annotations.NotNull method getX(): java.lang.String @@ -55,12 +56,14 @@ public final class OperatorsKt { private static @org.jetbrains.annotations.NotNull field a: A public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void + public final static @org.jetbrains.annotations.Nullable method checkCompareTo(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object public final static @org.jetbrains.annotations.Nullable method foo1(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object public final static @org.jetbrains.annotations.Nullable method foo2(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object public final static @org.jetbrains.annotations.Nullable method foo3(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object public final static @org.jetbrains.annotations.Nullable method foo4(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object public final static @org.jetbrains.annotations.Nullable method foo6(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object public final static @org.jetbrains.annotations.Nullable method foo7(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object + public final static @org.jetbrains.annotations.Nullable method foo9(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object public final static @org.jetbrains.annotations.NotNull method getA(): A public final static method setA(@org.jetbrains.annotations.NotNull p0: A): void public final static @org.jetbrains.annotations.Nullable method suspendThere(@org.jetbrains.annotations.NotNull p0: java.lang.String, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/operators.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/operators.kt new file mode 100644 index 00000000000..d643a8a8e78 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/operators.kt @@ -0,0 +1,28 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// SKIP_TXT + +class A { + suspend operator fun get(x: Int) = 1 + suspend operator fun set(x: Int, v: String) {} + + operator suspend fun contains(y: String): Boolean = true +} + +class B +suspend operator fun B.get(x: Int) =1 +suspend operator fun B.set(x: Int, v: String) {} + +operator suspend fun B.contains(y: String): Boolean = true + +class C { + suspend fun get(x: Int) = 1 + suspend fun set(x: Int, v: String) {} + + suspend fun contains(y: String): Boolean = true +} + +class D +suspend fun D.get(x: Int) =1 +suspend fun D.set(x: Int, v: String) {} + +suspend fun D.contains(y: String): Boolean = true diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index a624d42747a..f7f78c9ff21 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -773,6 +773,12 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW doTest(fileName); } + @TestMetadata("operators.kt") + public void testOperators() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/operators.kt"); + doTest(fileName); + } + @TestMetadata("suspendApplicability.kt") public void testSuspendApplicability() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/suspendApplicability.kt");