diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index 757372bb238..6765142b8b7 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -2789,6 +2789,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt"); } + @TestMetadata("symbolsAndDescriptors.kt") + public void testSymbolsAndDescriptors() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt"); + } + @TestMetadata("transform.kt") public void testTransform() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/problems/transform.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.fir.txt b/compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.fir.txt new file mode 100644 index 00000000000..f0836b5662f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.fir.txt @@ -0,0 +1,46 @@ +FILE: symbolsAndDescriptors.kt + public final class IrClassSymbolImpl : R|IrBindableSymbolBase|, R|IrClassSymbol| { + public constructor(descriptor: R|kotlin/String?| = Null(null)): R|IrClassSymbolImpl| { + super|>(R|/descriptor|) + } + + } + public abstract interface IrClassSymbol : R|IrClassifierSymbol|, R|IrBindableSymbol| { + } + public abstract interface IrClassifierSymbol : R|IrSymbol|, R|TypeConstructorMarker| { + public abstract override val descriptor: R|kotlin/CharSequence| + public get(): R|kotlin/CharSequence| + + } + public abstract interface IrSymbol : R|kotlin/Any| { + public abstract val descriptor: R|kotlin/Any| + public get(): R|kotlin/Any| + + } + public abstract interface TypeConstructorMarker : R|kotlin/Any| { + } + public abstract interface IrBindableSymbol : R|IrSymbol| { + public abstract override val descriptor: R|D| + public get(): R|D| + + } + public abstract class IrBindableSymbolBase : R|IrBindableSymbol|, R|IrSymbolBase| { + public constructor(descriptor: R|D?|): R|IrBindableSymbolBase| { + super|>(R|/descriptor|) + } + + } + public abstract class IrSymbolBase : R|IrSymbol| { + public constructor(_descriptor: R|D?|): R|IrSymbolBase| { + super() + } + + private final val _descriptor: R|D?| = R|/_descriptor| + private get(): R|D?| + + public open override val descriptor: R|D| + public get(): R|D| { + ^ this@R|/IrSymbolBase|.R|/IrSymbolBase._descriptor|!! + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt b/compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt new file mode 100644 index 00000000000..8ccb1f3be5b --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt @@ -0,0 +1,33 @@ +class IrClassSymbolImpl(descriptor: String? = null) : + IrBindableSymbolBase(descriptor), + IrClassSymbol + +interface IrClassSymbol : IrClassifierSymbol, IrBindableSymbol + +interface IrClassifierSymbol : IrSymbol, TypeConstructorMarker { + override val descriptor: CharSequence +} + +interface IrSymbol { + val descriptor: Any +} + +interface TypeConstructorMarker + +interface IrBindableSymbol : IrSymbol { + override val descriptor: D +} + +abstract class IrBindableSymbolBase(descriptor: D?) : + IrBindableSymbol, IrSymbolBase(descriptor) + +abstract class IrSymbolBase( + private val _descriptor: D? +) : IrSymbol { + override val descriptor: D + get() = _descriptor!! +} + + + + diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index a3540c37d43..235beae2374 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -3159,6 +3159,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt"); } + @Test + @TestMetadata("symbolsAndDescriptors.kt") + public void testSymbolsAndDescriptors() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt"); + } + @Test @TestMetadata("transform.kt") public void testTransform() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index cc5062f2deb..a7fb070b344 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -3159,6 +3159,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt"); } + @Test + @TestMetadata("symbolsAndDescriptors.kt") + public void testSymbolsAndDescriptors() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt"); + } + @Test @TestMetadata("transform.kt") public void testTransform() throws Exception { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt index 6c657be6d90..558ff6f7f8a 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirNotImplementedOverrideChecker.kt @@ -63,11 +63,58 @@ object FirNotImplementedOverrideChecker : FirClassChecker() { return false } + fun FirIntersectionCallableSymbol.subjectToManyNotImplemented(): Boolean { + var nonAbstractCountInClass = 0 + var nonAbstractCountInInterface = 0 + var abstractCountInInterface = 0 + for (intersectionSymbol in intersections) { + val intersection = intersectionSymbol.fir as FirCallableMemberDeclaration + val containingClass = intersection.getContainingClass(context) as? FirRegularClass + val hasInterfaceContainer = containingClass?.classKind == ClassKind.INTERFACE + if (intersection.modality != Modality.ABSTRACT) { + if (hasInterfaceContainer) { + nonAbstractCountInInterface++ + } else { + nonAbstractCountInClass++ + } + } else if (hasInterfaceContainer) { + abstractCountInInterface++ + } + if (nonAbstractCountInClass + nonAbstractCountInInterface > 1) { + return true + } + if (nonAbstractCountInInterface > 0 && abstractCountInInterface > 0) { + return true + } + } + return false + } + + fun FirIntersectionCallableSymbol.shouldBeImplemented(): Boolean { + // In Java 8, non-abstract intersection overrides having abstract symbol from base class + // still should be implemented in current class (even when they have default interface implementation) + if (intersections.none { + val fir = (it.fir as FirCallableMemberDeclaration).unwrapFakeOverrides() + fir.isAbstract && (fir.getContainingClass(context) as? FirRegularClass)?.classKind == ClassKind.CLASS + } + ) return false + // Exception from the rule above: interface implementation via delegation + if (intersections.any { + val fir = (it.fir as FirCallableMemberDeclaration) + fir.origin == FirDeclarationOrigin.Delegated && !fir.isAbstract + } + ) return false + return true + } + fun FirCallableMemberDeclaration<*>.shouldBeImplemented(): Boolean { - if (!isAbstract) return false val containingClass = getContainingClass(context) - if (containingClass === declaration && origin == FirDeclarationOrigin.Source) return false if (containingClass is FirRegularClass && containingClass.isExpect) return false + if (!isAbstract) { + val symbol = symbol as? FirIntersectionCallableSymbol ?: return false + return symbol.shouldBeImplemented() + } + if (containingClass === declaration && origin == FirDeclarationOrigin.Source) return false return true } @@ -75,9 +122,8 @@ object FirNotImplementedOverrideChecker : FirClassChecker() { classScope.processFunctionsByName(name) { namedFunctionSymbol -> val simpleFunction = namedFunctionSymbol.fir if (namedFunctionSymbol is FirIntersectionOverrideFunctionSymbol) { - if (namedFunctionSymbol.intersections.count { - (it.fir as FirCallableMemberDeclaration).modality != Modality.ABSTRACT - } > 1 && simpleFunction.getContainingClass(context) === declaration + if (simpleFunction.getContainingClass(context) === declaration && + namedFunctionSymbol.subjectToManyNotImplemented() ) { notImplementedIntersectionSymbols += namedFunctionSymbol return@processFunctionsByName @@ -99,9 +145,8 @@ object FirNotImplementedOverrideChecker : FirClassChecker() { classScope.processPropertiesByName(name) { propertySymbol -> val property = propertySymbol.fir as? FirProperty ?: return@processPropertiesByName if (propertySymbol is FirIntersectionOverridePropertySymbol) { - if (propertySymbol.intersections.count { - (it.fir as FirCallableMemberDeclaration).modality != Modality.ABSTRACT - } > 1 && property.getContainingClass(context) === declaration + if (property.getContainingClass(context) === declaration && + propertySymbol.subjectToManyNotImplemented() ) { notImplementedIntersectionSymbols += propertySymbol return@processPropertiesByName diff --git a/compiler/testData/codegen/box/bridges/fakeOverrideFromInterfaceThroughIntermediateClass.kt b/compiler/testData/codegen/box/bridges/fakeOverrideFromInterfaceThroughIntermediateClass.kt index 698b6a8bf27..f4e4a1d41b0 100644 --- a/compiler/testData/codegen/box/bridges/fakeOverrideFromInterfaceThroughIntermediateClass.kt +++ b/compiler/testData/codegen/box/bridges/fakeOverrideFromInterfaceThroughIntermediateClass.kt @@ -1,3 +1,6 @@ +// IGNORE_BACKEND_FIR: JVM_IR + +// Note: this test will fail in Kotlin 1.6 (see AbstractClassMemberNotImplementedWithIntermediateAbstractClass feature) interface A { fun foo(): Any } diff --git a/compiler/testData/codegen/box/bridges/fakeOverrideMultiFile.kt b/compiler/testData/codegen/box/bridges/fakeOverrideMultiFile.kt index af4180c9896..3ed6865c100 100644 --- a/compiler/testData/codegen/box/bridges/fakeOverrideMultiFile.kt +++ b/compiler/testData/codegen/box/bridges/fakeOverrideMultiFile.kt @@ -1,3 +1,6 @@ +// IGNORE_BACKEND_FIR: JVM_IR + +// Note: this test will fail in Kotlin 1.6 (see AbstractClassMemberNotImplementedWithIntermediateAbstractClass feature) // FILE: 1.kt class Test: Impl(), CProvider diff --git a/compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented.fir.kt b/compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented.fir.kt index 847548615e3..a6a61d7dbe2 100644 --- a/compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented.fir.kt +++ b/compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented.fir.kt @@ -8,11 +8,11 @@ interface IRight { fun foo() {} } -class CDerived : ALeft(), IRight +class CDerived : ALeft(), IRight abstract class CAbstract : ALeft(), IRight -class CDerivedFromAbstract : CAbstract() +class CDerivedFromAbstract : CAbstract() interface ILeft { fun foo() @@ -21,10 +21,10 @@ interface ILeft { abstract class AILeft : ILeft // Should be ERROR -class AILeftImpl : AILeft(), IRight +class AILeftImpl : AILeft(), IRight // Should be ERROR -class RightLeft : ILeft, IRight +class RightLeft : ILeft, IRight interface IBase { fun foo() diff --git a/compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented_15.fir.kt b/compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented_15.fir.kt index 104f23a4377..106fb665830 100644 --- a/compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented_15.fir.kt +++ b/compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented_15.fir.kt @@ -8,11 +8,11 @@ interface IRight { fun foo() {} } -class CDerived : ALeft(), IRight +class CDerived : ALeft(), IRight abstract class CAbstract : ALeft(), IRight -class CDerivedFromAbstract : CAbstract() +class CDerivedFromAbstract : CAbstract() interface ILeft { fun foo() @@ -21,10 +21,10 @@ interface ILeft { abstract class AILeft : ILeft // Should be ERROR -class AILeftImpl : AILeft(), IRight +class AILeftImpl : AILeft(), IRight // Should be ERROR -class RightLeft : ILeft, IRight +class RightLeft : ILeft, IRight interface IBase { fun foo() diff --git a/compiler/testData/diagnostics/tests/java8Overrides/defaultVsAbstract.fir.kt b/compiler/testData/diagnostics/tests/java8Overrides/defaultVsAbstract.fir.kt index 8dcd1d137ad..0d7901d14f0 100644 --- a/compiler/testData/diagnostics/tests/java8Overrides/defaultVsAbstract.fir.kt +++ b/compiler/testData/diagnostics/tests/java8Overrides/defaultVsAbstract.fir.kt @@ -8,6 +8,6 @@ interface IRight { interface IDerived : ILeft, IRight -class CDerived : ILeft, IRight +class CDerived : ILeft, IRight abstract class ADerived : ILeft, IRight \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/java8Overrides/kt45508.fir.kt b/compiler/testData/diagnostics/tests/java8Overrides/kt45508.fir.kt index 4226ff18864..74799931c57 100644 --- a/compiler/testData/diagnostics/tests/java8Overrides/kt45508.fir.kt +++ b/compiler/testData/diagnostics/tests/java8Overrides/kt45508.fir.kt @@ -8,11 +8,11 @@ interface B { open class D: B -open class C: D(), A +open class C: D(), A // ------------ -class Test: Impl(), CProvider +class Test: Impl(), CProvider open class CC diff --git a/compiler/testData/diagnostics/tests/override/FakeOverrideModality2.fir.kt b/compiler/testData/diagnostics/tests/override/FakeOverrideModality2.fir.kt deleted file mode 100644 index 3b5f283db50..00000000000 --- a/compiler/testData/diagnostics/tests/override/FakeOverrideModality2.fir.kt +++ /dev/null @@ -1,18 +0,0 @@ -interface A { - fun foo() {} -} - -interface B : A { - abstract override fun foo() -} - -interface C : A { - abstract override fun foo() -} - -interface D : A { - override fun foo() = super.foo() -} - -// Fake override Z#foo should be open -class Z : B, C, D diff --git a/compiler/testData/diagnostics/tests/override/FakeOverrideModality2.kt b/compiler/testData/diagnostics/tests/override/FakeOverrideModality2.kt index 77d7303a742..e54b350cea3 100644 --- a/compiler/testData/diagnostics/tests/override/FakeOverrideModality2.kt +++ b/compiler/testData/diagnostics/tests/override/FakeOverrideModality2.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL interface A { fun foo() {} } diff --git a/compiler/testData/diagnostics/tests/override/parameterNames/kotlinInheritsBothJavaAndKotlin.fir.kt b/compiler/testData/diagnostics/tests/override/parameterNames/kotlinInheritsBothJavaAndKotlin.fir.kt deleted file mode 100644 index 7845a3c17bc..00000000000 --- a/compiler/testData/diagnostics/tests/override/parameterNames/kotlinInheritsBothJavaAndKotlin.fir.kt +++ /dev/null @@ -1,13 +0,0 @@ -// FILE: JavaInterface.java - -interface JavaInterface { - void foo(int javaName); -} - -// FILE: kotlin.kt - -interface KotlinTrait { - public fun foo(someOtherName: Int) {} -} - -class BothTraitsSubclass : JavaInterface, KotlinTrait \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/override/parameterNames/kotlinInheritsBothJavaAndKotlin.kt b/compiler/testData/diagnostics/tests/override/parameterNames/kotlinInheritsBothJavaAndKotlin.kt index 021256a8568..da318aa7caa 100644 --- a/compiler/testData/diagnostics/tests/override/parameterNames/kotlinInheritsBothJavaAndKotlin.kt +++ b/compiler/testData/diagnostics/tests/override/parameterNames/kotlinInheritsBothJavaAndKotlin.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // FILE: JavaInterface.java interface JavaInterface { diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCallAmbiguity2.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCallAmbiguity2.fir.kt index cd2701cd0c0..cde952cd170 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCallAmbiguity2.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCallAmbiguity2.fir.kt @@ -25,7 +25,7 @@ class D : B, A { } } -class E: B, A { +class E: B, A { fun foo() { super.test() } diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCallAmbiguity3.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCallAmbiguity3.fir.kt index 8df79b04f13..923f86ef6ee 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCallAmbiguity3.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmDefault/superCallAmbiguity3.fir.kt @@ -24,7 +24,7 @@ class D : B, A { } } -class E: B, A { +class E: B, A { fun foo() { super.test() } diff --git a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.10.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.10.fir.kt index 7c7c9d71819..f02cd10b96a 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.10.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/declarations/classifier-declaration/class-declaration/abstract-classes/p-2/neg/1.10.fir.kt @@ -4,7 +4,7 @@ // FULL_JDK // TESTCASE NUMBER: 1 -class Case1() : BaseCase1(), InterfaceCase1 {} +class Case1() : BaseCase1(), InterfaceCase1 {} abstract class BaseCase1() { abstract fun foo(): String