diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java index c371b0a12f7..72c70cfa2c6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java @@ -379,40 +379,68 @@ public class OverrideResolver { Set relevantDirectlyOverridden = getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations); - int implCount = countImplementations(relevantDirectlyOverridden); - if (implCount == 0) { - collectNotSynthesizedDescriptorsByModality(allFilteredOverriddenDeclarations, abstractNoImpl, Modality.ABSTRACT); + List implementations = collectImplementations(relevantDirectlyOverridden); + if (implementations.size() == 1 && isReturnTypeOkForOverride(descriptor, implementations.get(0))) return; + + List abstractOverridden = new ArrayList(allFilteredOverriddenDeclarations.size()); + List concreteOverridden = new ArrayList(allFilteredOverriddenDeclarations.size()); + filterNotSynthesizedDescriptorsByModality(allFilteredOverriddenDeclarations, abstractOverridden, concreteOverridden); + + if (implementations.isEmpty()) { + abstractNoImpl.addAll(abstractOverridden); } - else if (implCount > 1) { - collectNotSynthesizedDescriptorsByModality(allFilteredOverriddenDeclarations, manyImpl, Modality.OPEN, Modality.FINAL); + else if (implementations.size() > 1) { + manyImpl.addAll(concreteOverridden); + } + else { + abstractNoImpl.addAll(collectAbstractMethodsWithMoreSpecificReturnType(abstractOverridden, implementations.get(0))); } } - private static int countImplementations(@NotNull Set relevantDirectlyOverridden) { - int implCount = 0; + @NotNull + private static List collectImplementations(@NotNull Set relevantDirectlyOverridden) { + List result = new ArrayList(relevantDirectlyOverridden.size()); for (CallableMemberDescriptor overriddenDescriptor : relevantDirectlyOverridden) { if (overriddenDescriptor.getModality() != Modality.ABSTRACT) { - implCount++; + result.add(overriddenDescriptor); } } - return implCount; + return result; } - private static void collectNotSynthesizedDescriptorsByModality( + private static void filterNotSynthesizedDescriptorsByModality( @NotNull Set allOverriddenDeclarations, - @NotNull Set result, - Modality... modalities + @NotNull List abstractOverridden, + @NotNull List concreteOverridden ) { - Set modalitySet = Sets.newHashSet(modalities); for (CallableMemberDescriptor overridden : allOverriddenDeclarations) { - if (modalitySet.contains(overridden.getModality())) { - if (!CallResolverUtil.isOrOverridesSynthesized(overridden)) { - result.add(overridden); + if (!CallResolverUtil.isOrOverridesSynthesized(overridden)) { + if (overridden.getModality() == Modality.ABSTRACT) { + abstractOverridden.add(overridden); + } + else { + concreteOverridden.add(overridden); } } } } + @NotNull + private static List collectAbstractMethodsWithMoreSpecificReturnType( + @NotNull List abstractOverridden, + @NotNull CallableMemberDescriptor implementation + ) { + List result = new ArrayList(abstractOverridden.size()); + for (CallableMemberDescriptor abstractMember : abstractOverridden) { + if (!isReturnTypeOkForOverride(abstractMember, implementation)) { + result.add(abstractMember); + } + } + assert !result.isEmpty() : "Implementation (" + implementation + ") doesn't have the most specific type, " + + "but none of the other overridden methods does either: " + abstractOverridden; + return result; + } + @NotNull private static Set getRelevantDirectlyOverridden( @NotNull Map> overriddenByParent, diff --git a/compiler/testData/codegen/box/classes/selfcreate.kt b/compiler/testData/codegen/box/classes/selfcreate.kt index 1c78c067719..4423f0e84a9 100644 --- a/compiler/testData/codegen/box/classes/selfcreate.kt +++ b/compiler/testData/codegen/box/classes/selfcreate.kt @@ -1,7 +1,7 @@ class B () {} open class A(val b : B) { - fun a() = object: A(b) {} + fun a(): A = object: A(b) {} } fun box() : String { diff --git a/compiler/testData/codegen/bytecodeText/bridgeForFakeOverride.kt b/compiler/testData/codegen/bytecodeText/bridgeForFakeOverride.kt index afa807eb43e..1b9a31ed573 100644 --- a/compiler/testData/codegen/bytecodeText/bridgeForFakeOverride.kt +++ b/compiler/testData/codegen/bytecodeText/bridgeForFakeOverride.kt @@ -1,5 +1,5 @@ trait A { - fun foo(): Object + fun foo(): Any } open class B { diff --git a/compiler/testData/diagnostics/tests/override/FakeOverrideDifferentDeclarationSignatures.kt b/compiler/testData/diagnostics/tests/override/FakeOverrideDifferentDeclarationSignatures.kt new file mode 100644 index 00000000000..553f9044b9f --- /dev/null +++ b/compiler/testData/diagnostics/tests/override/FakeOverrideDifferentDeclarationSignatures.kt @@ -0,0 +1,11 @@ +trait A { + fun f(): String = "string" +} + +open class B { + open fun f(): CharSequence = "charSequence" +} + +class C : B(), A + +val obj: A = object : B(), A {} diff --git a/compiler/testData/diagnostics/tests/override/kt4763.kt b/compiler/testData/diagnostics/tests/override/kt4763.kt new file mode 100644 index 00000000000..0bf001885ad --- /dev/null +++ b/compiler/testData/diagnostics/tests/override/kt4763.kt @@ -0,0 +1,11 @@ +trait A { + fun f(): String +} + +open class B { + open fun f(): CharSequence = "charSequence" +} + +class C : B(), A + +val d: A = object : B(), A {} diff --git a/compiler/testData/diagnostics/tests/override/kt4763property.kt b/compiler/testData/diagnostics/tests/override/kt4763property.kt new file mode 100644 index 00000000000..15e5cb97759 --- /dev/null +++ b/compiler/testData/diagnostics/tests/override/kt4763property.kt @@ -0,0 +1,11 @@ +trait P { + var f: Number +} + +open class Q { + val x: Int = 42 +} + +class R : P, Q() + +val s: Q = object : Q(), P {} diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 03e627b09ee..87305dd6230 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -5307,6 +5307,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/override/FakeOverrideAbstractAndNonAbstractFun.kt"); } + @TestMetadata("FakeOverrideDifferentDeclarationSignatures.kt") + public void testFakeOverrideDifferentDeclarationSignatures() throws Exception { + doTest("compiler/testData/diagnostics/tests/override/FakeOverrideDifferentDeclarationSignatures.kt"); + } + @TestMetadata("Generics.kt") public void testGenerics() throws Exception { doTest("compiler/testData/diagnostics/tests/override/Generics.kt"); @@ -5327,6 +5332,16 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest("compiler/testData/diagnostics/tests/override/kt2052.kt"); } + @TestMetadata("kt4763.kt") + public void testKt4763() throws Exception { + doTest("compiler/testData/diagnostics/tests/override/kt4763.kt"); + } + + @TestMetadata("kt4763property.kt") + public void testKt4763property() throws Exception { + doTest("compiler/testData/diagnostics/tests/override/kt4763property.kt"); + } + @TestMetadata("kt4785.kt") public void testKt4785() throws Exception { doTest("compiler/testData/diagnostics/tests/override/kt4785.kt"); diff --git a/idea/testData/diagnosticMessage/wrongReturnTypeInImplementation.kt b/idea/testData/diagnosticMessage/wrongReturnTypeInImplementation.kt new file mode 100644 index 00000000000..6870ed12458 --- /dev/null +++ b/idea/testData/diagnosticMessage/wrongReturnTypeInImplementation.kt @@ -0,0 +1,27 @@ +// !DIAGNOSTICS_NUMBER: 1 +// !DIAGNOSTICS: ABSTRACT_MEMBER_NOT_IMPLEMENTED +// !MESSAGE_TYPE: TEXT + +trait T1 +trait T2 : T1 +trait T3 : T2 +trait T4 : T3 + + +trait A { + fun f(): T1 +} + +trait B { + fun f(): T2 = null!! +} + +trait C { + fun f(): T3 +} + +abstract class D { + abstract fun f(): T4 +} + +class E : A, B, C, D() diff --git a/idea/testData/diagnosticMessage/wrongReturnTypeInImplementation1.txt b/idea/testData/diagnosticMessage/wrongReturnTypeInImplementation1.txt new file mode 100644 index 00000000000..981c291fe45 --- /dev/null +++ b/idea/testData/diagnosticMessage/wrongReturnTypeInImplementation1.txt @@ -0,0 +1,2 @@ + +Class 'E' must be declared abstract or implement abstract member internal abstract fun f(): T3 defined in C \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/plugin/highlighter/DiagnosticMessageTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/highlighter/DiagnosticMessageTestGenerated.java index 6148d25316f..fb2309f084c 100644 --- a/idea/tests/org/jetbrains/jet/plugin/highlighter/DiagnosticMessageTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/highlighter/DiagnosticMessageTestGenerated.java @@ -146,4 +146,9 @@ public class DiagnosticMessageTestGenerated extends AbstractDiagnosticMessageTes doTest("idea/testData/diagnosticMessage/upperBoundViolated.kt"); } + @TestMetadata("wrongReturnTypeInImplementation.kt") + public void testWrongReturnTypeInImplementation() throws Exception { + doTest("idea/testData/diagnosticMessage/wrongReturnTypeInImplementation.kt"); + } + }