diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/unqualifiedSuper/unqualifiedSuper.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/unqualifiedSuper/unqualifiedSuper.kt index 1ea32a529b8..e0117087d9c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/unqualifiedSuper/unqualifiedSuper.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/unqualifiedSuper/unqualifiedSuper.kt @@ -31,6 +31,7 @@ import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.psi.KtSuperExpression import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.utils.addToStdlib.singletonList @@ -121,25 +122,36 @@ private fun resolveSupertypesByPropertyName(supertypes: Collection, private inline fun resolveSupertypesByMembers( supertypes: Collection, - allowArbitraryMembers: Boolean, + allowNonConcreteMembers: Boolean, getMembers: (KotlinType) -> Collection ): Collection { val typesWithConcreteMembers = SmartList() - val typesWithArbitraryMembers = SmartList() + val typesWithNonConcreteMembers = SmartList() for (supertype in supertypes) { val members = getMembers(supertype) if (members.isNotEmpty()) { - typesWithArbitraryMembers.add(supertype) - if (members.any { isConcreteMember(supertype, it) }) { + if (members.any { isConcreteMember(supertype, it) }) typesWithConcreteMembers.add(supertype) - } + else + typesWithNonConcreteMembers.add(supertype) } } - return if (typesWithConcreteMembers.isNotEmpty()) typesWithConcreteMembers - else if (allowArbitraryMembers) typesWithArbitraryMembers - else emptyList() + typesWithConcreteMembers.removeAll { typeWithConcreteMember -> + typesWithNonConcreteMembers.any { typeWithNonConcreteMember -> + KotlinTypeChecker.DEFAULT.isSubtypeOf(typeWithNonConcreteMember, typeWithConcreteMember) + } + } + + return when { + typesWithConcreteMembers.isNotEmpty() -> + typesWithConcreteMembers + allowNonConcreteMembers -> + typesWithNonConcreteMembers + else -> + emptyList() + } } private fun getFunctionMembers(type: KotlinType, name: Name, location: LookupLocation): Collection = diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.kt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.kt new file mode 100644 index 00000000000..3a004145de5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.kt @@ -0,0 +1,29 @@ +interface A { + fun foo() {} +} + +abstract class C : A { + override abstract fun foo() +} + +interface Unrelated { + fun foo() {} +} + +class Test1 : C(), A { + override fun foo() { + // Abstract 'foo' defined in 'C' wins against non-abstract 'foo' defined in 'A', + // because 'C' is a subclass of 'A' (and 'C::foo' overrides 'A::foo'), + // even though 'A' is explicitly listed in supertypes list for 'D'. + super.foo() + } +} + +class Test2 : C(), A, Unrelated { + override fun foo() { + // This is ok, because there's a non-abstract 'foo' in 'Unrelated', + // which is not overridden by abstract 'foo' in 'C'. + super.foo() + super.foo() + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.txt b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.txt new file mode 100644 index 00000000000..ccb62db91a6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.txt @@ -0,0 +1,39 @@ +package + +public interface A { + 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 abstract class C : A { + public constructor C() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract 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 Test1 : C, A { + public constructor Test1() + public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*2*/ fun foo(): kotlin.Unit + public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Test2 : C, A, Unrelated { + public constructor Test2() + public open override /*3*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*3*/ fun foo(): kotlin.Unit + public open override /*3*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*3*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Unrelated { + 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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 823ce3cbce9..9dd36f1a320 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -21783,6 +21783,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("withMethodOverriddenInAnotherSupertype.kt") + public void testWithMethodOverriddenInAnotherSupertype() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodOverriddenInAnotherSupertype.kt"); + doTest(fileName); + } + @TestMetadata("withMethodsOfAny.kt") public void testWithMethodsOfAny() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodsOfAny.kt");