From d188de3086c6cffe307d8c52aee6342fa02cd83e Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 7 Mar 2017 18:02:46 +0300 Subject: [PATCH] KT-6014 Wrong ABSTRACT_MEMBER_NOT_IMPLEMENTED for toString implemented by delegation Members declared in interface or overriding members declared in super-interfaces can be implemented by delegation even if they override members declared in super-class (NB for interface this can be only 'kotlin.Any'). --- .../kotlin/resolve/DelegationResolver.kt | 26 +++++------- .../diagnostics/tests/override/kt6014.kt | 17 ++++++++ .../diagnostics/tests/override/kt6014.txt | 41 +++++++++++++++++++ .../checkers/DiagnosticsTestGenerated.java | 6 +++ 4 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/override/kt6014.kt create mode 100644 compiler/testData/diagnostics/tests/override/kt6014.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegationResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegationResolver.kt index e9edba8397b..018f3542a7d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegationResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegationResolver.kt @@ -28,7 +28,6 @@ import org.jetbrains.kotlin.psi.KtTypeReference import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE import org.jetbrains.kotlin.resolve.lazy.DelegationFilter import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.isDynamic import org.jetbrains.kotlin.utils.keysToMapExceptNulls @@ -91,20 +90,17 @@ class DelegationResolver private constructor( } - private fun getDelegatableMembers(interfaceType: KotlinType): Collection { - val classSupertypeMembers = - TypeUtils.getAllSupertypes(interfaceType).firstOrNull { - val typeConstructor = it.constructor.declarationDescriptor - typeConstructor is ClassDescriptor && typeConstructor.kind != ClassKind.INTERFACE - }?.let { - memberExtractor.getMembersByType(it) - } ?: emptyList() - return memberExtractor.getMembersByType(interfaceType).filter { descriptor -> - descriptor.isOverridable && - !classSupertypeMembers.any { isOverridableBy(it, descriptor) } && - delegationFilter.filter(descriptor, languageVersionSettings) - } - } + private fun getDelegatableMembers(interfaceType: KotlinType): Collection = + memberExtractor.getMembersByType(interfaceType).filter { descriptor -> + descriptor.isOverridable && + (descriptor.kind.isReal || !descriptor.overridesClassMembersOnly()) && + delegationFilter.filter(descriptor, languageVersionSettings) + } + + private fun T.overridesClassMembersOnly() = + DescriptorUtils.getAllOverriddenDeclarations(this).all { + DescriptorUtils.isClass(it.containingDeclaration) + } interface MemberExtractor { fun getMembersByType(type: KotlinType): Collection diff --git a/compiler/testData/diagnostics/tests/override/kt6014.kt b/compiler/testData/diagnostics/tests/override/kt6014.kt new file mode 100644 index 00000000000..a8ecad03d8d --- /dev/null +++ b/compiler/testData/diagnostics/tests/override/kt6014.kt @@ -0,0 +1,17 @@ +interface IBase { + override fun toString(): String +} + +interface IDerived : IBase + +object BaseImpl : IBase { + override fun toString(): String = "A" +} + +object DerivedImpl : IDerived { + override fun toString(): String = "A" +} + +class Test1 : IBase by BaseImpl + +class Test2 : IDerived by DerivedImpl diff --git a/compiler/testData/diagnostics/tests/override/kt6014.txt b/compiler/testData/diagnostics/tests/override/kt6014.txt new file mode 100644 index 00000000000..4f6d5a6944f --- /dev/null +++ b/compiler/testData/diagnostics/tests/override/kt6014.txt @@ -0,0 +1,41 @@ +package + +public object BaseImpl : IBase { + private constructor BaseImpl() + 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*/ fun toString(): kotlin.String +} + +public object DerivedImpl : IDerived { + private constructor DerivedImpl() + 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*/ fun toString(): kotlin.String +} + +public interface IBase { + 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 abstract override /*1*/ fun toString(): kotlin.String +} + +public interface IDerived : IBase { + 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 abstract override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Test1 : IBase { + public constructor Test1() + 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*/ /*delegation*/ fun toString(): kotlin.String +} + +public final class Test2 : IDerived { + public constructor Test2() + 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*/ /*delegation*/ 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 9dd36f1a320..cf360dcb14a 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -14332,6 +14332,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("kt6014.kt") + public void testKt6014() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/override/kt6014.kt"); + doTest(fileName); + } + @TestMetadata("kt880.kt") public void testKt880() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/override/kt880.kt");