KT-13342 Unqualified super call should not resolve to a method of supertype overridden in another supertype

This commit is contained in:
Dmitry Petrov
2017-03-07 16:13:29 +03:00
parent 954c1d853d
commit 9a2c9ed30e
4 changed files with 94 additions and 8 deletions
@@ -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<KotlinType>,
private inline fun resolveSupertypesByMembers(
supertypes: Collection<KotlinType>,
allowArbitraryMembers: Boolean,
allowNonConcreteMembers: Boolean,
getMembers: (KotlinType) -> Collection<MemberDescriptor>
): Collection<KotlinType> {
val typesWithConcreteMembers = SmartList<KotlinType>()
val typesWithArbitraryMembers = SmartList<KotlinType>()
val typesWithNonConcreteMembers = SmartList<KotlinType>()
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<KotlinType>()
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<MemberDescriptor> =
@@ -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.<!ABSTRACT_SUPER_CALL!>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<Unrelated>.foo()
}
}
@@ -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
}
@@ -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");