From de9c41c412e3f5e871f287a7df42516f7082d288 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Thu, 12 Jan 2017 11:25:37 +0300 Subject: [PATCH] Fix overridability rules for suspend functions Treat suspend and non-suspend functions as conflicting #KT-15413 Fixed --- .../tests/coroutines/mixingSuspendability.kt | 6 +++ .../tests/coroutines/mixingSuspendability.txt | 23 ++++++++++ .../suspendConflictsWithNoSuspend.kt | 15 +++++++ .../suspendConflictsWithNoSuspend.txt | 17 +++++++ .../tests/coroutines/suspendOverridability.kt | 37 ++++++++++++++++ .../coroutines/suspendOverridability.txt | 44 +++++++++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 18 ++++++++ .../kotlin/resolve/OverridingUtil.java | 5 +++ 8 files changed, 165 insertions(+) create mode 100644 compiler/testData/diagnostics/tests/coroutines/mixingSuspendability.kt create mode 100644 compiler/testData/diagnostics/tests/coroutines/mixingSuspendability.txt create mode 100644 compiler/testData/diagnostics/tests/coroutines/suspendConflictsWithNoSuspend.kt create mode 100644 compiler/testData/diagnostics/tests/coroutines/suspendConflictsWithNoSuspend.txt create mode 100644 compiler/testData/diagnostics/tests/coroutines/suspendOverridability.kt create mode 100644 compiler/testData/diagnostics/tests/coroutines/suspendOverridability.txt diff --git a/compiler/testData/diagnostics/tests/coroutines/mixingSuspendability.kt b/compiler/testData/diagnostics/tests/coroutines/mixingSuspendability.kt new file mode 100644 index 00000000000..09b234d6b86 --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/mixingSuspendability.kt @@ -0,0 +1,6 @@ +interface AsyncVal { suspend fun getVal(): Int = 1} +interface SyncVal { fun getVal(): Int = 1 } + +class MixSuspend : AsyncVal, SyncVal { + +} diff --git a/compiler/testData/diagnostics/tests/coroutines/mixingSuspendability.txt b/compiler/testData/diagnostics/tests/coroutines/mixingSuspendability.txt new file mode 100644 index 00000000000..6dcbed01116 --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/mixingSuspendability.txt @@ -0,0 +1,23 @@ +package + +public interface AsyncVal { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open suspend fun getVal(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class MixSuspend : AsyncVal, SyncVal { + public constructor MixSuspend() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open suspend override /*1*/ /*fake_override*/ fun getVal(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface SyncVal { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun getVal(): kotlin.Int + 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/suspendConflictsWithNoSuspend.kt b/compiler/testData/diagnostics/tests/coroutines/suspendConflictsWithNoSuspend.kt new file mode 100644 index 00000000000..f262e1d15d2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/suspendConflictsWithNoSuspend.kt @@ -0,0 +1,15 @@ +// FILE: main.kt +interface A { + suspend fun foo() + fun foo() +} + +interface B : A { + suspend override fun foo() { + + } + + override fun foo() { + + } +} diff --git a/compiler/testData/diagnostics/tests/coroutines/suspendConflictsWithNoSuspend.txt b/compiler/testData/diagnostics/tests/coroutines/suspendConflictsWithNoSuspend.txt new file mode 100644 index 00000000000..e20ff4958f3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/suspendConflictsWithNoSuspend.txt @@ -0,0 +1,17 @@ +package + +public interface A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.Unit + public abstract suspend fun foo(): 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 : A { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun foo(): kotlin.Unit + public open suspend override /*1*/ fun foo(): kotlin.Unit + 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/suspendOverridability.kt b/compiler/testData/diagnostics/tests/coroutines/suspendOverridability.kt new file mode 100644 index 00000000000..fe6b33661c9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/suspendOverridability.kt @@ -0,0 +1,37 @@ +// FILE: main.kt +interface A { + suspend fun foo() + fun bar() +} + +interface B : A { + override fun foo() { + + } + + override suspend fun bar() { + + } +} + +interface C : A { + suspend override fun foo() { + + } + + override fun bar() { + + } +} + +class D : J { + suspend override fun foo() { + + } +} + +// FILE: J.java + +public interface J extends A { + Object foo(kotlin.coroutines.Continuation y); +} diff --git a/compiler/testData/diagnostics/tests/coroutines/suspendOverridability.txt b/compiler/testData/diagnostics/tests/coroutines/suspendOverridability.txt new file mode 100644 index 00000000000..c3beb0e87a2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/coroutines/suspendOverridability.txt @@ -0,0 +1,44 @@ +package + +public interface A { + public abstract fun bar(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract suspend fun foo(): 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 : A { + public open suspend fun bar(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open fun foo(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface C : A { + public open override /*1*/ fun bar(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open suspend override /*1*/ fun foo(): 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 D : J { + public constructor D() + public abstract override /*1*/ /*fake_override*/ fun bar(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open suspend override /*1*/ fun foo(): kotlin.Unit + public abstract override /*1*/ /*fake_override*/ fun foo(/*0*/ y: kotlin.coroutines.Continuation!): kotlin.Any! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface J : A { + public abstract override /*1*/ /*fake_override*/ fun bar(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract suspend override /*1*/ /*fake_override*/ fun foo(): kotlin.Unit + public abstract fun foo(/*0*/ y: kotlin.coroutines.Continuation!): kotlin.Any! + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + 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 d1e6e5dfc66..a23d24c82bd 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -4318,6 +4318,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("mixingSuspendability.kt") + public void testMixingSuspendability() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/mixingSuspendability.kt"); + doTest(fileName); + } + @TestMetadata("noDefaultCoroutineImports.kt") public void testNoDefaultCoroutineImports() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/noDefaultCoroutineImports.kt"); @@ -4336,6 +4342,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("suspendConflictsWithNoSuspend.kt") + public void testSuspendConflictsWithNoSuspend() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/suspendConflictsWithNoSuspend.kt"); + doTest(fileName); + } + @TestMetadata("suspendCoroutineOrReturn.kt") public void testSuspendCoroutineOrReturn() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/suspendCoroutineOrReturn.kt"); @@ -4354,6 +4366,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("suspendOverridability.kt") + public void testSuspendOverridability() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/suspendOverridability.kt"); + doTest(fileName); + } + @TestMetadata("tryCatchLambda.kt") public void testTryCatchLambda() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/tryCatchLambda.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java index 80a9bf027f1..93ac9423f05 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/OverridingUtil.java @@ -260,6 +260,11 @@ public class OverridingUtil { } } + if (superDescriptor instanceof FunctionDescriptor && subDescriptor instanceof FunctionDescriptor && + ((FunctionDescriptor) superDescriptor).isSuspend() != ((FunctionDescriptor) subDescriptor).isSuspend()) { + return OverrideCompatibilityInfo.conflict("Incompatible suspendability"); + } + if (checkReturnType) { KotlinType superReturnType = superDescriptor.getReturnType(); KotlinType subReturnType = subDescriptor.getReturnType();