diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 01a50a9c52f..a0e28980a04 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -23652,6 +23652,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/override/DelegationVar.kt"); } + @Test + @TestMetadata("diamondWithDiagonal.kt") + public void testDiamondWithDiagonal() throws Exception { + runTest("compiler/testData/diagnostics/tests/override/diamondWithDiagonal.kt"); + } + @Test @TestMetadata("DuplicateMethod.kt") public void testDuplicateMethod() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java index 1c757ce1e16..64afb2df738 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java @@ -23652,6 +23652,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/override/DelegationVar.kt"); } + @Test + @TestMetadata("diamondWithDiagonal.kt") + public void testDiamondWithDiagonal() throws Exception { + runTest("compiler/testData/diagnostics/tests/override/diamondWithDiagonal.kt"); + } + @Test @TestMetadata("DuplicateMethod.kt") public void testDuplicateMethod() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index dcb856a232b..453eb831873 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -23658,6 +23658,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/override/DelegationVar.kt"); } + @Test + @TestMetadata("diamondWithDiagonal.kt") + public void testDiamondWithDiagonal() throws Exception { + runTest("compiler/testData/diagnostics/tests/override/diamondWithDiagonal.kt"); + } + @Test @TestMetadata("DuplicateMethod.kt") public void testDuplicateMethod() throws Exception { diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt index 10f4d397227..f02f26196aa 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt @@ -152,24 +152,25 @@ class FirTypeIntersectionScopeContext( val groupWithPrivate = overrideService.extractBothWaysOverridable(allMembersWithScope.maxByVisibility(), allMembersWithScope, overrideChecker) val group = groupWithPrivate.filter { !Visibilities.isPrivate(it.member.fir.visibility) }.ifEmpty { groupWithPrivate } - val directOverrides = if (forClassUseSiteScope) group.onlyDirectlyInherited() else group - val mostSpecific = overrideService.selectMostSpecificMembers(directOverrides, ReturnTypeCalculatorForFullBodyResolve) + val nonSubsumed = if (forClassUseSiteScope) group.nonSubsumed() else group + val mostSpecific = overrideService.selectMostSpecificMembers(nonSubsumed, ReturnTypeCalculatorForFullBodyResolve) val nonTrivial = if (forClassUseSiteScope) { // Create a non-trivial intersection override when the base methods come from different scopes, - // even if one of them is more specific than the others. This is necessary for proper reporting of - // MANY_{IMPL,INTERFACES}_MEMBER_NOT_IMPLEMENTED diagnostics. + // even if one of them is more specific than the others, i.e. when there is more than one method that is not subsumed. + // This is necessary for proper reporting of MANY_{IMPL,INTERFACES}_MEMBER_NOT_IMPLEMENTED diagnostics. // // It is also possible to have the opposite case (> 1 most specific member, but all members are from // the same base scope), but this means there are different instantiations of the same base class, // which should generally result in INCONSISTENT_TYPE_PARAMETER_VALUES errors. - directOverrides.size > 1 && - directOverrides.mapTo(mutableSetOf()) { it.member.fir.unwrapSubstitutionOverrides().symbol }.size > 1 + nonSubsumed.size > 1 && + nonSubsumed.mapTo(mutableSetOf()) { it.member.fir.unwrapSubstitutionOverrides().symbol }.size > 1 } else { // Create a non-trivial intersection override when return types should be intersected. mostSpecific.size > 1 } if (nonTrivial) { - result += ResultOfIntersection.NonTrivial(this, mostSpecific, group, containingScope = null) + // Only add non-subsumed members to list of overridden in intersection override. + result += ResultOfIntersection.NonTrivial(this, mostSpecific, overriddenMembers = nonSubsumed, containingScope = null) } else { val (member, containingScope) = mostSpecific.first() result += ResultOfIntersection.SingleMember(member, group, containingScope) @@ -209,12 +210,16 @@ class FirTypeIntersectionScopeContext( }.withScope(key.baseScope) } - private fun > List>.onlyDirectlyInherited(): List> { + /** + * A callable declaration D [subsumes](https://kotlinlang.org/spec/inheritance.html#matching-and-subsumption-of-declarations) + * a callable declaration B if D overrides B. + */ + private fun > List>.nonSubsumed(): List> { val baseMembers = mutableSetOf>() for ((member, scope) in this) { - val unwrapped = member.fir.unwrapSubstitutionOverrides().symbol + val unwrapped = member.unwrapSubstitutionOverrides>() val addIfDifferent = { it: FirCallableSymbol<*> -> - val symbol = it.fir.unwrapSubstitutionOverrides().symbol + val symbol = it.unwrapSubstitutionOverrides() if (symbol != unwrapped) { baseMembers += symbol } @@ -226,7 +231,7 @@ class FirTypeIntersectionScopeContext( scope.processOverriddenProperties(member, addIfDifferent) } } - return filter { it.member.fir.unwrapSubstitutionOverrides().symbol !in baseMembers } + return filter { it.member.unwrapSubstitutionOverrides>() !in baseMembers } } private fun > Collection>.maxByVisibility(): MemberWithBaseScope { @@ -301,15 +306,6 @@ class FirTypeIntersectionScopeContext( return result } - private inline fun D.unwrapSubstitutionOverrides(): D { - var current = this - - do { - val next = current.originalForSubstitutionOverride ?: return current - current = next - } while (true) - } - private fun > collectRealOverridden( symbol: D, scope: FirTypeScope, diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt index 3f33b9c7166..aab02cde5b1 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/ClassMembers.kt @@ -111,6 +111,8 @@ inline fun D.unwrapSubstitutionOverrides(): inline fun > S.unwrapFakeOverrides(): S = fir.unwrapFakeOverrides().symbol as S +inline fun > S.unwrapSubstitutionOverrides(): S = fir.unwrapSubstitutionOverrides().symbol as S + private object SubstitutedOverrideOriginalKey : FirDeclarationDataKey() var diff --git a/compiler/testData/diagnostics/tests/override/FakeOverrideModality3.fir.kt b/compiler/testData/diagnostics/tests/override/FakeOverrideModality3.fir.kt deleted file mode 100644 index 9aca1afc65f..00000000000 --- a/compiler/testData/diagnostics/tests/override/FakeOverrideModality3.fir.kt +++ /dev/null @@ -1,16 +0,0 @@ -interface A { - fun foo() {} -} - -interface B : A { - abstract override fun foo() -} - -interface C : A { - abstract override fun foo() -} - -interface D : A - -// Fake override Z#foo should be abstract -class Z : B, C, D diff --git a/compiler/testData/diagnostics/tests/override/FakeOverrideModality3.kt b/compiler/testData/diagnostics/tests/override/FakeOverrideModality3.kt index 485981df58d..e199f95f23d 100644 --- a/compiler/testData/diagnostics/tests/override/FakeOverrideModality3.kt +++ b/compiler/testData/diagnostics/tests/override/FakeOverrideModality3.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL interface A { fun foo() {} } diff --git a/compiler/testData/diagnostics/tests/override/diamondWithDiagonal.kt b/compiler/testData/diagnostics/tests/override/diamondWithDiagonal.kt new file mode 100644 index 00000000000..e7434c668e4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/override/diamondWithDiagonal.kt @@ -0,0 +1,21 @@ +// SKIP_TXT +// FIR_IDENTICAL +// ISSUE: KT-57092 + +interface InterfaceWithDefault { + val hostKind: Int get() = 24 +} + +interface SubInterfaceWithoutDefault : InterfaceWithDefault { + // SubInterfaceWithoutDefault.hostKind subsumes InterfaceWithDefault.hostKind, therefore no error. + override val hostKind: Int +} + +open class ClassWithDefault : InterfaceWithDefault { + override val hostKind: Int get() = 42 +} + +class InheritsAll : + ClassWithDefault(), + SubInterfaceWithoutDefault, + InterfaceWithDefault diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index f4400d034bb..aa4ab5cdc8d 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -23658,6 +23658,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/override/DelegationVar.kt"); } + @Test + @TestMetadata("diamondWithDiagonal.kt") + public void testDiamondWithDiagonal() throws Exception { + runTest("compiler/testData/diagnostics/tests/override/diamondWithDiagonal.kt"); + } + @Test @TestMetadata("DuplicateMethod.kt") public void testDuplicateMethod() throws Exception {