diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/abstractSuperCallInPresenseOfNonAbstractMethodInParent.kt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/abstractSuperCallInPresenseOfNonAbstractMethodInParent.kt new file mode 100644 index 00000000000..23e7fc1dfcb --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/abstractSuperCallInPresenseOfNonAbstractMethodInParent.kt @@ -0,0 +1,17 @@ +// ISSUE: KT-38400 + +interface IWithToString { + override fun toString(): String + fun foo(): String + fun bar(): String +} + +open class B { + open fun foo(): String = "" +} + +class A : IWithToString, B() { + override fun toString(): String = super.toString() // resolve to Any.toString + override fun foo(): String = super.foo() // resolve to B.foo() + override fun bar(): String = super.bar() // should be an error +} diff --git a/compiler/fir/analysis-tests/testData/resolve/diagnostics/abstractSuperCallInPresenseOfNonAbstractMethodInParent.txt b/compiler/fir/analysis-tests/testData/resolve/diagnostics/abstractSuperCallInPresenseOfNonAbstractMethodInParent.txt new file mode 100644 index 00000000000..47473b3321e --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/diagnostics/abstractSuperCallInPresenseOfNonAbstractMethodInParent.txt @@ -0,0 +1,37 @@ +FILE: abstractSuperCallInPresenseOfNonAbstractMethodInParent.kt + public abstract interface IWithToString : R|kotlin/Any| { + public abstract override fun toString(): R|kotlin/String| + + public abstract fun foo(): R|kotlin/String| + + public abstract fun bar(): R|kotlin/String| + + } + public open class B : R|kotlin/Any| { + public constructor(): R|B| { + super() + } + + public open fun foo(): R|kotlin/String| { + ^foo String() + } + + } + public final class A : R|IWithToString|, R|B| { + public constructor(): R|A| { + super() + } + + public final override fun toString(): R|kotlin/String| { + ^toString this@R|/A|.super.R|kotlin/Any.toString|() + } + + public final override fun foo(): R|kotlin/String| { + ^foo this@R|/A|.super.R|/B.foo|() + } + + public final override fun bar(): R|kotlin/String| { + ^bar this@R|/A|.super.R|/IWithToString.bar|() + } + + } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index bcf53399382..00c706e3f4e 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -937,6 +937,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/abstractSuperCall.kt"); } + @TestMetadata("abstractSuperCallInPresenseOfNonAbstractMethodInParent.kt") + public void testAbstractSuperCallInPresenseOfNonAbstractMethodInParent() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/abstractSuperCallInPresenseOfNonAbstractMethodInParent.kt"); + } + public void testAllFilesPresentInDiagnostics() throws Exception { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/diagnostics"), Pattern.compile("^([^.]+)\\.kt$"), null, true); } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java index 4af78f35bac..40dfc73e8a0 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -937,6 +937,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/abstractSuperCall.kt"); } + @TestMetadata("abstractSuperCallInPresenseOfNonAbstractMethodInParent.kt") + public void testAbstractSuperCallInPresenseOfNonAbstractMethodInParent() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/abstractSuperCallInPresenseOfNonAbstractMethodInParent.kt"); + } + public void testAllFilesPresentInDiagnostics() throws Exception { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/diagnostics"), Pattern.compile("^([^.]+)\\.kt$"), null, true); } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt index fe739ec3ab0..3a719cf1528 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.resolve.calls +import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirExpression @@ -103,6 +104,13 @@ internal sealed class CheckReceivers : ResolutionStage() { val explicitReceiverExpression = callInfo.explicitReceiver val explicitReceiverKind = candidate.explicitReceiverKind + if (explicitReceiverExpression.isSuperCall()) { + val status = candidate.symbol.fir as? FirMemberDeclaration + if (status?.modality == Modality.ABSTRACT) { + sink.reportDiagnostic(ResolvedWithLowPriority) + } + } + if (expectedReceiverType != null) { if (explicitReceiverExpression != null && explicitReceiverKind.shouldBeCheckedAgainstExplicit() && @@ -136,6 +144,11 @@ internal sealed class CheckReceivers : ResolutionStage() { } } } + + private fun FirExpression?.isSuperCall(): Boolean { + if (this !is FirQualifiedAccessExpression) return false + return calleeReference is FirSuperReference + } } private fun FirExpression.isSuperReferenceExpression(): Boolean {