From c884cffeea5e51f0ffa7778e3e8fe41295806610 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 26 Sep 2016 20:54:10 +0300 Subject: [PATCH] Prohibit return type mismatch for delegation members #KT-13952 Fixed #KT-13005 Fixed --- .../jetbrains/kotlin/diagnostics/Errors.java | 4 ++ .../rendering/DefaultErrorMessages.java | 4 ++ .../kotlin/resolve/OverrideResolver.java | 14 ++++-- .../covariantOverrides/fromClass.kt | 19 +++++++ .../covariantOverrides/fromClass.txt | 49 +++++++++++++++++++ .../covariantOverrides/irrelevant.kt | 19 +++++++ .../covariantOverrides/irrelevant.txt | 47 ++++++++++++++++++ .../delegation/covariantOverrides/kt13952.kt | 17 +++++++ .../delegation/covariantOverrides/kt13952.txt | 39 +++++++++++++++ .../delegation/covariantOverrides/simple.kt | 19 +++++++ .../delegation/covariantOverrides/simple.txt | 47 ++++++++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 33 +++++++++++++ 12 files changed, 306 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/delegation/covariantOverrides/fromClass.kt create mode 100644 compiler/testData/diagnostics/tests/delegation/covariantOverrides/fromClass.txt create mode 100644 compiler/testData/diagnostics/tests/delegation/covariantOverrides/irrelevant.kt create mode 100644 compiler/testData/diagnostics/tests/delegation/covariantOverrides/irrelevant.txt create mode 100644 compiler/testData/diagnostics/tests/delegation/covariantOverrides/kt13952.kt create mode 100644 compiler/testData/diagnostics/tests/delegation/covariantOverrides/kt13952.txt create mode 100644 compiler/testData/diagnostics/tests/delegation/covariantOverrides/simple.kt create mode 100644 compiler/testData/diagnostics/tests/delegation/covariantOverrides/simple.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 847d04c7998..c7d40aecce3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -363,6 +363,10 @@ public interface Errors { DiagnosticFactory2.create(ERROR, DECLARATION_NAME); DiagnosticFactory2 VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION = DiagnosticFactory2.create(ERROR, DECLARATION_NAME); + DiagnosticFactory2 RETURN_TYPE_MISMATCH_BY_DELEGATION = + DiagnosticFactory2.create(ERROR, DECLARATION_NAME); + DiagnosticFactory2 PROPERTY_TYPE_MISMATCH_BY_DELEGATION = + DiagnosticFactory2.create(ERROR, DECLARATION_NAME); DiagnosticFactory2> CONFLICTING_INHERITED_MEMBERS = DiagnosticFactory2.create(ERROR, DECLARATION_NAME); 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 cf1f83127a3..2043a7c5c24 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -613,6 +613,10 @@ public class DefaultErrorMessages { SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES); MAP.put(VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION, "Val-property ''{0}'' implicitly overrides a var-property ''{1}'' by delegation", SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES); + MAP.put(RETURN_TYPE_MISMATCH_BY_DELEGATION, "Type of ''{0}'' is not a subtype of overridden by delegation ''{1}''", + SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES); + MAP.put(PROPERTY_TYPE_MISMATCH_BY_DELEGATION, "Type of property ''{0}'' is not a subtype of overridden by delegation ''{1}''", + SHORT_NAMES_IN_TYPES, SHORT_NAMES_IN_TYPES); MAP.put(VAR_OVERRIDDEN_BY_VAL, "Var-property {0} cannot be overridden by val-property {1}", FQ_NAMES_IN_TYPES, FQ_NAMES_IN_TYPES); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverrideResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverrideResolver.java index 4932e020ec2..4f655efdea5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverrideResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/OverrideResolver.java @@ -240,7 +240,7 @@ public class OverrideResolver { @Override public void overridingFinalMember(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) { - reportDelegationProblemIfRequired(OVERRIDING_FINAL_MEMBER_BY_DELEGATION, overriding, overridden); + reportDelegationProblemIfRequired(OVERRIDING_FINAL_MEMBER_BY_DELEGATION, null, overriding, overridden); } @Override @@ -248,7 +248,8 @@ public class OverrideResolver { @NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden ) { - // Always reported as RETURN_TYPE_MISMATCH_ON_INHERITANCE + reportDelegationProblemIfRequired( + RETURN_TYPE_MISMATCH_BY_DELEGATION, RETURN_TYPE_MISMATCH_ON_INHERITANCE, overriding, overridden); } @Override @@ -256,22 +257,25 @@ public class OverrideResolver { @NotNull PropertyDescriptor overriding, @NotNull PropertyDescriptor overridden ) { - // Always reported as PROPERTY_TYPE_MISMATCH_ON_INHERITANCE + reportDelegationProblemIfRequired( + PROPERTY_TYPE_MISMATCH_BY_DELEGATION, PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, overriding, overridden); } @Override public void varOverriddenByVal(@NotNull CallableMemberDescriptor overriding, @NotNull CallableMemberDescriptor overridden) { - reportDelegationProblemIfRequired(VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION, overriding, overridden); + reportDelegationProblemIfRequired(VAR_OVERRIDDEN_BY_VAL_BY_DELEGATION, null, overriding, overridden); } private void reportDelegationProblemIfRequired( @NotNull DiagnosticFactory2 diagnosticFactory, + @Nullable DiagnosticFactoryWithPsiElement relevantDiagnosticFromInheritance, @NotNull CallableMemberDescriptor delegate, @NotNull CallableMemberDescriptor overridden ) { assert delegate.getKind() == DELEGATION : "Delegate expected, got " + delegate + " of kind " + delegate.getKind(); - if (!onceErrorsReported.contains(diagnosticFactory)) { + if (!onceErrorsReported.contains(diagnosticFactory) && + (relevantDiagnosticFromInheritance == null || !onceErrorsReported.contains(relevantDiagnosticFromInheritance))) { onceErrorsReported.add(diagnosticFactory); trace.report(diagnosticFactory.on(klass, delegate, overridden)); } diff --git a/compiler/testData/diagnostics/tests/delegation/covariantOverrides/fromClass.kt b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/fromClass.kt new file mode 100644 index 00000000000..6ce44d79dd6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/fromClass.kt @@ -0,0 +1,19 @@ +interface IBase1 { + fun foo(): Any +} + +open class IDerived1 : IBase1 { + override fun foo(): String = "1" +} + +class Broken1(val b: IBase1) : IBase1 by b, IDerived1() + +interface IBase2 { + val foo: Any +} + +open class IDerived2 : IBase2 { + override val foo: String = "2" +} + +class Broken2(val b: IBase2) : IBase2 by b, IDerived2() diff --git a/compiler/testData/diagnostics/tests/delegation/covariantOverrides/fromClass.txt b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/fromClass.txt new file mode 100644 index 00000000000..0ba9782fd47 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/fromClass.txt @@ -0,0 +1,49 @@ +package + +public final class Broken1 : IBase1, IDerived1 { + public constructor Broken1(/*0*/ b: IBase1) + public final val b: IBase1 + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*delegation*/ fun foo(): kotlin.Any + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Broken2 : IBase2, IDerived2 { + public constructor Broken2(/*0*/ b: IBase2) + public final val b: IBase2 + public open override /*2*/ /*delegation*/ val foo: kotlin.Any + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IBase1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.Any + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IBase2 { + public abstract val foo: kotlin.Any + 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 open class IDerived1 : IBase1 { + public constructor IDerived1() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun foo(): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class IDerived2 : IBase2 { + public constructor IDerived2() + public open override /*1*/ val foo: kotlin.String = "2" + 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/delegation/covariantOverrides/irrelevant.kt b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/irrelevant.kt new file mode 100644 index 00000000000..0c3dc5f7016 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/irrelevant.kt @@ -0,0 +1,19 @@ +interface IBase1 { + fun foo(): Any +} + +interface IDerived1 { + fun foo(): String +} + +class Broken1(val b: IBase1) : IBase1 by b, IDerived1 + +interface IBase2 { + val foo: Any +} + +interface IDerived2 { + val foo: String +} + +class Broken2(val b: IBase2) : IBase2 by b, IDerived2 diff --git a/compiler/testData/diagnostics/tests/delegation/covariantOverrides/irrelevant.txt b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/irrelevant.txt new file mode 100644 index 00000000000..5cffab25bb9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/irrelevant.txt @@ -0,0 +1,47 @@ +package + +public final class Broken1 : IBase1, IDerived1 { + public constructor Broken1(/*0*/ b: IBase1) + public final val b: IBase1 + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*delegation*/ fun foo(): kotlin.Any + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Broken2 : IBase2, IDerived2 { + public constructor Broken2(/*0*/ b: IBase2) + public final val b: IBase2 + public open override /*2*/ /*delegation*/ val foo: kotlin.Any + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IBase1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.Any + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IBase2 { + public abstract val foo: kotlin.Any + 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 interface IDerived1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IDerived2 { + public abstract val foo: 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 +} diff --git a/compiler/testData/diagnostics/tests/delegation/covariantOverrides/kt13952.kt b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/kt13952.kt new file mode 100644 index 00000000000..100585fdc5b --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/kt13952.kt @@ -0,0 +1,17 @@ +interface IA { + fun foo(): Number +} + +interface IB : IA { + override fun foo(): Int +} + +object AImpl : IA { + override fun foo() = 42 +} + +open class C : IA by AImpl, IB + +class D : C() { + override fun foo(): Double = 3.14 +} diff --git a/compiler/testData/diagnostics/tests/delegation/covariantOverrides/kt13952.txt b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/kt13952.txt new file mode 100644 index 00000000000..08b604615c8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/kt13952.txt @@ -0,0 +1,39 @@ +package + +public object AImpl : IA { + private constructor AImpl() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun foo(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class C : IA, IB { + public constructor C() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*delegation*/ fun foo(): kotlin.Number + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class D : C { + public constructor D() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ fun foo(): kotlin.Double + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IA { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.Number + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IB : IA { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ fun foo(): 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/delegation/covariantOverrides/simple.kt b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/simple.kt new file mode 100644 index 00000000000..ef16b6cc8fa --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/simple.kt @@ -0,0 +1,19 @@ +interface IBase1 { + fun foo(): Any +} + +interface IDerived1 : IBase1 { + override fun foo(): String +} + +class Broken1(val b: IBase1) : IBase1 by b, IDerived1 + +interface IBase2 { + val foo: Any +} + +interface IDerived2 : IBase2 { + override val foo: String +} + +class Broken2(val b: IBase2) : IBase2 by b, IDerived2 diff --git a/compiler/testData/diagnostics/tests/delegation/covariantOverrides/simple.txt b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/simple.txt new file mode 100644 index 00000000000..db89f815bc2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegation/covariantOverrides/simple.txt @@ -0,0 +1,47 @@ +package + +public final class Broken1 : IBase1, IDerived1 { + public constructor Broken1(/*0*/ b: IBase1) + public final val b: IBase1 + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*delegation*/ fun foo(): kotlin.Any + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Broken2 : IBase2, IDerived2 { + public constructor Broken2(/*0*/ b: IBase2) + public final val b: IBase2 + public open override /*2*/ /*delegation*/ val foo: kotlin.Any + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IBase1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun foo(): kotlin.Any + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IBase2 { + public abstract val foo: kotlin.Any + 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 interface IDerived1 : IBase1 { + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract override /*1*/ fun foo(): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface IDerived2 : IBase2 { + public abstract override /*1*/ val foo: 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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 9d72fc44285..eb75bfda199 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -5780,6 +5780,39 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } } + + @TestMetadata("compiler/testData/diagnostics/tests/delegation/covariantOverrides") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class CovariantOverrides extends AbstractDiagnosticsTest { + public void testAllFilesPresentInCovariantOverrides() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/delegation/covariantOverrides"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("fromClass.kt") + public void testFromClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegation/covariantOverrides/fromClass.kt"); + doTest(fileName); + } + + @TestMetadata("irrelevant.kt") + public void testIrrelevant() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegation/covariantOverrides/irrelevant.kt"); + doTest(fileName); + } + + @TestMetadata("kt13952.kt") + public void testKt13952() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegation/covariantOverrides/kt13952.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/delegation/covariantOverrides/simple.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/diagnostics/tests/deparenthesize")