diff --git a/compiler/fir/analysis-tests/testData/resolve/openInInterface.kt b/compiler/fir/analysis-tests/testData/resolve/openInInterface.kt new file mode 100644 index 00000000000..b1fb9400c42 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/openInInterface.kt @@ -0,0 +1,15 @@ +interface Some { + open fun foo() + open fun bar() {} + + open val x: Int + open val y = 1 + open val z get() = 1 + + open var xx: Int + open var yy = 1 + open var zz: Int + set(value) { + field = value + } +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolve/openInInterface.txt b/compiler/fir/analysis-tests/testData/resolve/openInInterface.txt new file mode 100644 index 00000000000..ebddf27a4c7 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/openInInterface.txt @@ -0,0 +1,33 @@ +FILE: openInInterface.kt + public abstract interface Some : R|kotlin/Any| { + public abstract fun foo(): R|kotlin/Unit| + + public open fun bar(): R|kotlin/Unit| { + } + + public abstract val x: R|kotlin/Int| + public get(): R|kotlin/Int| + + public open val y: R|kotlin/Int| = Int(1) + public get(): R|kotlin/Int| + + public open val z: R|kotlin/Int| + public get(): R|kotlin/Int| { + ^ Int(1) + } + + public abstract var xx: R|kotlin/Int| + public get(): R|kotlin/Int| + public set(value: R|kotlin/Int|): R|kotlin/Unit| + + public open var yy: R|kotlin/Int| = Int(1) + public get(): R|kotlin/Int| + public set(value: R|kotlin/Int|): R|kotlin/Unit| + + public open var zz: R|kotlin/Int| + public get(): R|kotlin/Int| + public set(value: R|kotlin/Int|): R|kotlin/Unit| { + this@R|/Some|.F|/Some.zz| = R|/value| + } + + } 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 40360adcc11..e6f6db5e04a 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 @@ -313,6 +313,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/analysis-tests/testData/resolve/offOrderMultiBoundGenericOverride.kt"); } + @TestMetadata("openInInterface.kt") + public void testOpenInInterface() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/openInInterface.kt"); + } + @TestMetadata("problems2.kt") public void testProblems2() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/problems2.kt"); 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 601ca9b8f41..456baab903f 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 @@ -313,6 +313,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/offOrderMultiBoundGenericOverride.kt"); } + @TestMetadata("openInInterface.kt") + public void testOpenInInterface() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/openInInterface.kt"); + } + @TestMetadata("problems2.kt") public void testProblems2() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/problems2.kt"); diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt index 47003b8779a..d6851bfe7c9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirStatusResolveTransformer.kt @@ -183,7 +183,7 @@ fun FirDeclaration.resolveStatus( containingClass: FirClass<*>?, isLocal: Boolean ): FirDeclarationStatus { - if (status.visibility == Visibilities.UNKNOWN || status.modality == null) { + if (status.visibility == Visibilities.UNKNOWN || status.modality == null || status.modality == Modality.OPEN) { val visibility = when (status.visibility) { Visibilities.UNKNOWN -> when { isLocal -> Visibilities.LOCAL @@ -192,12 +192,26 @@ fun FirDeclaration.resolveStatus( } else -> status.visibility } - val modality = status.modality ?: resolveModality(containingClass) + val modality = status.modality?.let { + if (it == Modality.OPEN && containingClass?.classKind == ClassKind.INTERFACE && !hasOwnBodyOrAccessorBody()) { + Modality.ABSTRACT + } else { + it + } + } ?: resolveModality(containingClass) return (status as FirDeclarationStatusImpl).resolved(visibility, modality) } return status } +private fun FirDeclaration.hasOwnBodyOrAccessorBody(): Boolean { + return when (this) { + is FirSimpleFunction -> this.body != null + is FirProperty -> this.initializer != null || this.getter?.body != null || this.setter?.body != null + else -> true + } +} + private fun FirDeclaration.resolveVisibility(containingClass: FirClass<*>?): Visibility { // See DescriptorUtils#getDefaultConstructorVisibility in core.descriptors if (this is FirConstructor) { @@ -221,9 +235,7 @@ private fun FirDeclaration.resolveModality(containingClass: FirClass<*>?): Modal when { visibility == Visibilities.PRIVATE -> Modality.FINAL - this is FirSimpleFunction && body == null -> - Modality.ABSTRACT - this is FirProperty && initializer == null && getter?.body == null && setter?.body == null -> + !this.hasOwnBodyOrAccessorBody() -> Modality.ABSTRACT else -> Modality.OPEN diff --git a/compiler/testData/codegen/box/classes/delegation3.kt b/compiler/testData/codegen/box/classes/delegation3.kt index 6ac66daa6d0..fd4f07800a2 100644 --- a/compiler/testData/codegen/box/classes/delegation3.kt +++ b/compiler/testData/codegen/box/classes/delegation3.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR interface One { public open fun foo() : Int public open fun faz() : Int = 10