KT-13342 Unqualified super call should not resolve to a method of supertype overridden in another supertype
This commit is contained in:
+20
-8
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
|||||||
import org.jetbrains.kotlin.psi.KtSuperExpression
|
import org.jetbrains.kotlin.psi.KtSuperExpression
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
||||||
|
|
||||||
|
|
||||||
@@ -121,25 +122,36 @@ private fun resolveSupertypesByPropertyName(supertypes: Collection<KotlinType>,
|
|||||||
|
|
||||||
private inline fun resolveSupertypesByMembers(
|
private inline fun resolveSupertypesByMembers(
|
||||||
supertypes: Collection<KotlinType>,
|
supertypes: Collection<KotlinType>,
|
||||||
allowArbitraryMembers: Boolean,
|
allowNonConcreteMembers: Boolean,
|
||||||
getMembers: (KotlinType) -> Collection<MemberDescriptor>
|
getMembers: (KotlinType) -> Collection<MemberDescriptor>
|
||||||
): Collection<KotlinType> {
|
): Collection<KotlinType> {
|
||||||
val typesWithConcreteMembers = SmartList<KotlinType>()
|
val typesWithConcreteMembers = SmartList<KotlinType>()
|
||||||
val typesWithArbitraryMembers = SmartList<KotlinType>()
|
val typesWithNonConcreteMembers = SmartList<KotlinType>()
|
||||||
|
|
||||||
for (supertype in supertypes) {
|
for (supertype in supertypes) {
|
||||||
val members = getMembers(supertype)
|
val members = getMembers(supertype)
|
||||||
if (members.isNotEmpty()) {
|
if (members.isNotEmpty()) {
|
||||||
typesWithArbitraryMembers.add(supertype)
|
if (members.any { isConcreteMember(supertype, it) })
|
||||||
if (members.any { isConcreteMember(supertype, it) }) {
|
|
||||||
typesWithConcreteMembers.add(supertype)
|
typesWithConcreteMembers.add(supertype)
|
||||||
}
|
else
|
||||||
|
typesWithNonConcreteMembers.add(supertype)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (typesWithConcreteMembers.isNotEmpty()) typesWithConcreteMembers
|
typesWithConcreteMembers.removeAll { typeWithConcreteMember ->
|
||||||
else if (allowArbitraryMembers) typesWithArbitraryMembers
|
typesWithNonConcreteMembers.any { typeWithNonConcreteMember ->
|
||||||
else emptyList<KotlinType>()
|
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> =
|
private fun getFunctionMembers(type: KotlinType, name: Name, location: LookupLocation): Collection<MemberDescriptor> =
|
||||||
|
|||||||
+29
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+39
@@ -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);
|
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")
|
@TestMetadata("withMethodsOfAny.kt")
|
||||||
public void testWithMethodsOfAny() throws Exception {
|
public void testWithMethodsOfAny() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodsOfAny.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/thisAndSuper/unqualifiedSuper/withMethodsOfAny.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user