diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java index 93568707faf..4b20766a086 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated.java @@ -1297,9 +1297,15 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst } @Test - @TestMetadata("morePermissiveVisibilityOnActualViaTypeAlias.kt") - public void testMorePermissiveVisibilityOnActualViaTypeAlias() throws Exception { - runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias.kt"); + @TestMetadata("morePermissiveVisibilityOnActualViaTypeAlias_finalMember.kt") + public void testMorePermissiveVisibilityOnActualViaTypeAlias_finalMember() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_finalMember.kt"); + } + + @Test + @TestMetadata("morePermissiveVisibilityOnActualViaTypeAlias_openMember.kt") + public void testMorePermissiveVisibilityOnActualViaTypeAlias_openMember() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_openMember.kt"); } @Test diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java index 7a1acef0740..0ff0ecefd5e 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendMPPDiagnosticsWithPsiTestGenerated.java @@ -1297,9 +1297,15 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi } @Test - @TestMetadata("morePermissiveVisibilityOnActualViaTypeAlias.kt") - public void testMorePermissiveVisibilityOnActualViaTypeAlias() throws Exception { - runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias.kt"); + @TestMetadata("morePermissiveVisibilityOnActualViaTypeAlias_finalMember.kt") + public void testMorePermissiveVisibilityOnActualViaTypeAlias_finalMember() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_finalMember.kt"); + } + + @Test + @TestMetadata("morePermissiveVisibilityOnActualViaTypeAlias_openMember.kt") + public void testMorePermissiveVisibilityOnActualViaTypeAlias_openMember() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_openMember.kt"); } @Test diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ActualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ActualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker.kt index 5fe2520817a..6e266e6d596 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ActualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ActualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker.kt @@ -10,16 +10,16 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingTrace -import org.jetbrains.kotlin.resolve.descriptorUtil.* +import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualCompatibilityChecker +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces +import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.multiplatform.* import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.source.KotlinSourceElement -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker -import java.util.* import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract @@ -142,198 +142,71 @@ private fun calculateExpectActualScopeDiff( parentSubstitutor = null ) - val expectClassCallables = expect.unsubstitutedMemberScope - .extractNonPrivateCallables(classTypeSubstitutor, ExpectActual.EXPECT, matchingContext) - val actualClassCallables = actual.unsubstitutedMemberScope - .extractNonPrivateCallables(classTypeSubstitutor, ExpectActual.ACTUAL, matchingContext) - .filter { it.descriptor.kind.isReal } // Filter out fake-overrides from actual because we compare list of supertypes separately anyway + val expectClassCallables = expect.unsubstitutedMemberScope.extractNonPrivateCallables() + val actualClassCallables = actual.unsubstitutedMemberScope.extractNonPrivateCallables() + .filter { it.kind.isReal } // Filter out fake-overrides from actual because we compare list of supertypes separately anyway - val nameAndKindToExpectCallable = expectClassCallables.groupBy { it.name to it.kind } + val nameAndKindToExpectCallables = expectClassCallables.groupBy { it.name to it.functionVsPropertyKind } - return (actualClassCallables - expectClassCallables).asSequence() - .flatMap { unmatchedActualCallable -> - when (val expectCallablesWithTheSameNameAndKind = - nameAndKindToExpectCallable[unmatchedActualCallable.name to unmatchedActualCallable.kind]) { - null -> listOf(ExpectActualMemberDiff.Kind.NonPrivateCallableAdded) - else -> expectCallablesWithTheSameNameAndKind.map { - calculateExpectActualMemberDiffKind( - expect = it, - actual = unmatchedActualCallable, - checkParameterNames = unmatchedActualCallable.descriptor.hasStableParameterNames() + return actualClassCallables.flatMap { actualMember -> + val potentialExpects = nameAndKindToExpectCallables[actualMember.name to actualMember.functionVsPropertyKind] + if (potentialExpects.isNullOrEmpty()) { + listOf(ExpectActualMemberDiff.Kind.NonPrivateCallableAdded) + } else { + potentialExpects + .map { expectMember -> + val substitutor = matchingContext.createExpectActualTypeParameterSubstitutor( + expectMember.typeParameters, + actualMember.typeParameters, + classTypeSubstitutor + ) + AbstractExpectActualCompatibilityChecker.getCallablesCompatibility( + expectMember, + actualMember, + substitutor, + expect, + actual, + matchingContext ) } - }.filterNotNull().map { kind -> ExpectActualMemberDiff(kind, unmatchedActualCallable.descriptor, expect) } + .takeIf { kinds -> kinds.all { it != ExpectActualCompatibility.Compatible } } + .orEmpty() + .map { + when (it) { + is ExpectActualCompatibility.Compatible -> error("Compatible was filtered out by takeIf") + is ExpectActualCompatibility.Incompatible -> it.toMemberDiffKind() + // If toMemberDiffKind returns null then some Kotlin invariants described in toMemberDiffKind no longer hold. + // We can't throw exception here because it would crash the compilation. + // Those broken invariants just needs to be reported by other checkers. + // But it's better to report some error (ExpectActualMemberDiff.Kind.NonPrivateCallableAdded in our case) to + // make sure that we don't have missed compilation errors if the invariants change + ?: ExpectActualMemberDiff.Kind.NonPrivateCallableAdded + } + } } - .toSet() + .map { kind -> ExpectActualMemberDiff(kind, actualMember, expect) } + }.toSet() } -private fun MemberScope.extractNonPrivateCallables( - classTypeSubstitutor: TypeSubstitutorMarker, - expectActual: ExpectActual, - matchingContext: ClassicExpectActualMatchingContext, -): Set { +private fun MemberScope.extractNonPrivateCallables(): Sequence { val functions = getFunctionNames().asSequence().flatMap { getContributedFunctions(it, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS) } val properties = getVariableNames().asSequence().flatMap { getContributedVariables(it, NoLookupLocation.WHEN_GET_ALL_DESCRIPTORS) } return (functions + properties).filter { !Visibilities.isPrivate(it.visibility.delegate) } - .map { descriptor -> Callable(descriptor, expectActual, classTypeSubstitutor, matchingContext) } - .toSet() } -private data class Parameter(val name: Name, val type: KotlinType) private enum class Kind { FUNCTION, PROPERTY } -private enum class ExpectActual { EXPECT, ACTUAL } -private data class TypeParameter(val name: Name, val upperBounds: List) -private class Callable( - val descriptor: CallableMemberDescriptor, - val expectActual: ExpectActual, - val classTypeSubstitutor: TypeSubstitutorMarker, - val matchingContext: ClassicExpectActualMatchingContext, -) { - val name: Name = descriptor.name - val kind: Kind = when (descriptor) { +private val CallableMemberDescriptor.functionVsPropertyKind: Kind + get() = when (this) { is PropertyDescriptor -> Kind.PROPERTY is FunctionDescriptor -> Kind.FUNCTION - else -> error("Unknown kind $descriptor") + else -> error("Unknown kind $this") } - val isVarProperty: Boolean = descriptor is PropertyDescriptor && descriptor.isVar - val isLateinitProperty: Boolean = descriptor is PropertyDescriptor && descriptor.isLateInit - val modality: Modality = descriptor.modality - val visibility: Visibility = descriptor.visibility.delegate - val setterVisibility: Visibility? = (descriptor as? PropertyDescriptor)?.setter?.visibility?.delegate - val parameters: List = descriptor.valueParameters.map { Parameter(it.name, it.type) } - val returnType: KotlinType = descriptor.returnType ?: error("Can't get return type") - val extensionReceiverType: KotlinType? = descriptor.extensionReceiverParameter?.type - val typeParameters: List = descriptor.typeParameters.map { TypeParameter(it.name, it.upperBounds) } - val contextReceiverTypes: List = descriptor.contextReceiverParameters.map(ValueDescriptor::getType) - - override fun equals(other: Any?): Boolean { - if (other !is Callable) return false - check(classTypeSubstitutor === other.classTypeSubstitutor) - check(matchingContext === other.matchingContext) - return if (expectActual == other.expectActual) { - name == other.name && - kind == other.kind && - isVarProperty == other.isVarProperty && - isLateinitProperty == other.isLateinitProperty && - modality == other.modality && - visibility == other.visibility && - setterVisibility == other.setterVisibility && - parameters == other.parameters && - returnType == other.returnType && - extensionReceiverType == other.extensionReceiverType && - typeParameters == other.typeParameters && - contextReceiverTypes == other.contextReceiverTypes - } else { - val (expect, actual) = if (expectActual == ExpectActual.EXPECT) this to other else other to this - calculateExpectActualMemberDiffKind(expect, actual) == null - } - } - - override fun hashCode(): Int = // Don't hash the types because type comparison is complicated - Objects.hash( - name, - kind, - isVarProperty, - isLateinitProperty, - modality, - visibility, - setterVisibility, - parameters.map(Parameter::name), - extensionReceiverType != null, - typeParameters.map(TypeParameter::name), - contextReceiverTypes.size, - ) -} private val CallableMemberDescriptor.psiIfReal: KtCallableDeclaration? get() = takeIf { it.kind.isReal }?.source?.let { it as? KotlinSourceElement }?.psi as? KtCallableDeclaration -private fun ClassicExpectActualMatchingContext.areCompatibleWithSubstitution( - expect: KotlinType?, - actual: KotlinType?, - substitutor: TypeSubstitutorMarker, -): Boolean = areCompatibleExpectActualTypes(expect?.let { substitutor.safeSubstitute(it) }, actual) - -private fun ClassicExpectActualMatchingContext.areCompatibleListWithSubstitution( - expect: List, - actual: List, - substitutor: TypeSubstitutorMarker, -): Boolean = expect.size == actual.size && expect.asSequence().zip(actual.asSequence()) - .all { (a, b) -> areCompatibleWithSubstitution(a, b, substitutor) } - -private fun ClassicExpectActualMatchingContext.areCompatibleUpperBoundsWithSubstitution( - expect: List>, - actual: List>, - substitutor: TypeSubstitutorMarker, -): Boolean = expect.size == actual.size && expect.asSequence().zip(actual.asSequence()) - .all { (a, b) -> areCompatibleListWithSubstitution(a, b, substitutor) } - -private fun calculateExpectActualMemberDiffKind( - expect: Callable, - actual: Callable, - checkParameterNames: Boolean = true, -): ExpectActualMemberDiff.Kind? { - check(expect.expectActual == ExpectActual.EXPECT) - check(actual.expectActual == ExpectActual.ACTUAL) - check(expect.classTypeSubstitutor === actual.classTypeSubstitutor) - check(expect.matchingContext === actual.matchingContext) - val substitutor = actual.matchingContext.createExpectActualTypeParameterSubstitutor( - expect.descriptor.typeParameters, - actual.descriptor.typeParameters, - actual.classTypeSubstitutor - ) - with(actual.matchingContext) { - return when { - expect.name != actual.name || - expect.kind != actual.kind || - !areCompatibleListWithSubstitution( - expect.parameters.map(Parameter::type), - actual.parameters.map(Parameter::type), - substitutor - ) || - !areCompatibleUpperBoundsWithSubstitution( - expect.typeParameters.map(TypeParameter::upperBounds), - actual.typeParameters.map(TypeParameter::upperBounds), - substitutor - ) || - !areCompatibleWithSubstitution( - expect.extensionReceiverType, - actual.extensionReceiverType, - substitutor - ) || - !areCompatibleListWithSubstitution( - expect.contextReceiverTypes, - actual.contextReceiverTypes, - substitutor - ) -> - ExpectActualMemberDiff.Kind.NonPrivateCallableAdded - - expect.isVarProperty != actual.isVarProperty -> ExpectActualMemberDiff.Kind.PropertyKindChangedInOverride - - expect.isLateinitProperty != actual.isLateinitProperty -> ExpectActualMemberDiff.Kind.LateinitChangedInOverride - - expect.modality != actual.modality -> ExpectActualMemberDiff.Kind.ModalityChangedInOverride - - expect.visibility != actual.visibility -> ExpectActualMemberDiff.Kind.VisibilityChangedInOverride - - expect.setterVisibility != actual.setterVisibility -> ExpectActualMemberDiff.Kind.SetterVisibilityChangedInOverride - - checkParameterNames && expect.parameters.map(Parameter::name) != actual.parameters.map(Parameter::name) -> - ExpectActualMemberDiff.Kind.ParameterNameChangedInOverride - - expect.typeParameters.map(TypeParameter::name) != actual.typeParameters.map(TypeParameter::name) -> - ExpectActualMemberDiff.Kind.TypeParameterNamesChangedInOverride - - !areCompatibleWithSubstitution(expect.returnType, actual.returnType, substitutor) -> - ExpectActualMemberDiff.Kind.ReturnTypeChangedInOverride - - else -> null - } - } -} - private fun BindingTrace.reportIfPossible(diff: ExpectActualMemberDiff) { val psi = diff.actualMember.psiIfReal ?: return val diagnostic = when (diff.kind) { diff --git a/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/finalMethodIsActualizedByOpenMethod.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/finalMethodIsActualizedByOpenMethod.fir.kt deleted file mode 100644 index 63b77ae33ab..00000000000 --- a/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/finalMethodIsActualizedByOpenMethod.fir.kt +++ /dev/null @@ -1,16 +0,0 @@ -// MODULE: m1-common -// FILE: common.kt - -expect open class Foo { - fun foo() -} - -// MODULE: m2-jvm()()(m1-common) -// FILE: jvm.kt - -actual open class Foo { - // Hypothetically, it's more restricting than necessary. I can't see how actualizing final -> open can breaking anything. - // But technically, actual and expect scopes don't match - actual open fun foo() { - } -} diff --git a/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/finalMethodIsActualizedByOpenMethod.kt b/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/finalMethodIsActualizedByOpenMethod.kt index 284512114cf..f53d3880bd3 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/finalMethodIsActualizedByOpenMethod.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/finalMethodIsActualizedByOpenMethod.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // MODULE: m1-common // FILE: common.kt @@ -8,9 +9,8 @@ expect open class Foo { // MODULE: m2-jvm()()(m1-common) // FILE: jvm.kt -actual open class Foo { - // Hypothetically, it's more restricting than necessary. I can't see how actualizing final -> open can breaking anything. - // But technically, actual and expect scopes don't match - actual open fun foo() { +actual open class Foo { + // final -> open is a legal modality change + actual open fun foo() { } } diff --git a/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/injectContextReceiverOverload.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/injectContextReceiverOverload.fir.kt index 857f40455a9..c5c3529517d 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/injectContextReceiverOverload.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/injectContextReceiverOverload.fir.kt @@ -12,6 +12,8 @@ expect open class Foo { actual open class Foo { actual fun foo() {} + // Expected: NON_ACTUAL_MEMBER_DECLARED_IN_EXPECT_NON_FINAL_CLASSIFIER_ACTUALIZATION. + // But it doesn't work because context receivers are not yet supported in expect actual matcher KT-61447 context(Int) - fun foo() {} // accidential override can happen with this injected fun. That's why it's prohibited + fun foo() {} } diff --git a/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/injectContextReceiverOverload.kt b/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/injectContextReceiverOverload.kt index 3157c2d1172..0a40fd8c1a1 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/injectContextReceiverOverload.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker/injectContextReceiverOverload.kt @@ -9,9 +9,11 @@ expect open class Foo { // MODULE: m2-jvm()()(m1-common) // FILE: jvm.kt -actual open class Foo { +actual open class Foo { actual fun foo() {} + // Expected: NON_ACTUAL_MEMBER_DECLARED_IN_EXPECT_NON_FINAL_CLASSIFIER_ACTUALIZATION. + // But it doesn't work because context receivers are not yet supported in expect actual matcher KT-61447 context(Int) - fun foo() {} // accidential override can happen with this injected fun. That's why it's prohibited + fun foo() {} } diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_finalMember.kt similarity index 95% rename from compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias.fir.kt rename to compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_finalMember.kt index 0fa39d9912f..6aa5a36e330 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_finalMember.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER // MODULE: m1-common // FILE: common.kt diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias.txt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_finalMember.txt similarity index 100% rename from compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias.txt rename to compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_finalMember.txt diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_openMember.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_openMember.fir.kt new file mode 100644 index 00000000000..80b62587d7a --- /dev/null +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_openMember.fir.kt @@ -0,0 +1,21 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +// MODULE: m1-common +// FILE: common.kt + +expect open class Container { + internal open fun internalFun() +} + +// MODULE: m2-jvm()()(m1-common) + +// FILE: foo/Foo.java + +package foo; + +public class Foo { + public void internalFun() {} +} + +// FILE: jvm.kt + +actual typealias Container = foo.Foo diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_openMember.kt similarity index 53% rename from compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias.kt rename to compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_openMember.kt index fa2a5b4943c..b1c8678b4df 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_openMember.kt @@ -3,7 +3,7 @@ // FILE: common.kt expect open class Container { - internal fun internalFun() + internal open fun internalFun() } // MODULE: m2-jvm()()(m1-common) @@ -13,9 +13,9 @@ expect open class Container { package foo; public class Foo { - public final void internalFun() {} + public void internalFun() {} } // FILE: jvm.kt -actual typealias Container = foo.Foo +actual typealias Container = foo.Foo 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 88ef1883c69..4f2fe12d715 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 @@ -24166,9 +24166,15 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { } @Test - @TestMetadata("morePermissiveVisibilityOnActualViaTypeAlias.kt") - public void testMorePermissiveVisibilityOnActualViaTypeAlias() throws Exception { - runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias.kt"); + @TestMetadata("morePermissiveVisibilityOnActualViaTypeAlias_finalMember.kt") + public void testMorePermissiveVisibilityOnActualViaTypeAlias_finalMember() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_finalMember.kt"); + } + + @Test + @TestMetadata("morePermissiveVisibilityOnActualViaTypeAlias_openMember.kt") + public void testMorePermissiveVisibilityOnActualViaTypeAlias_openMember() throws Exception { + runTest("compiler/testData/diagnostics/tests/multiplatform/headerClass/morePermissiveVisibilityOnActualViaTypeAlias_openMember.kt"); } @Test diff --git a/core/compiler.common/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectActualMemberDiff.kt b/core/compiler.common/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectActualMemberDiff.kt index 987c779a9b3..84a4d35532e 100644 --- a/core/compiler.common/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectActualMemberDiff.kt +++ b/core/compiler.common/src/org/jetbrains/kotlin/resolve/multiplatform/ExpectActualMemberDiff.kt @@ -10,7 +10,7 @@ data class ExpectActualMemberDiff(val kind: Kind, val actualMember /** * Diff kinds that are legal for fake-overrides in final `expect class`, but illegal for non-final `expect class` * - * Also see: [toDiffKind] + * Also see: [toMemberDiffKind] */ enum class Kind(val rawMessage: String) { NonPrivateCallableAdded( @@ -52,37 +52,31 @@ data class ExpectActualMemberDiff(val kind: Kind, val actualMember } } -/** - * This function serves a purpose of type-safe documentation. A mapping can be established between [ExpectActualCompatibility.Incompatible] - * and [ExpectActualMemberDiff.Kind]. This exhaustive when fixates this mapping, ensuring that we won't forget to add new - * [ExpectActualMemberDiff.Kind] when [ExpectActualCompatibility.Incompatible] is updated. - */ -@Suppress("unused") // The function is a documentation. That's why it's unused -private fun ExpectActualCompatibility.Incompatible<*>.toDiffKind(): ExpectActualMemberDiff.Kind? = when (this) { +fun ExpectActualCompatibility.Incompatible<*>.toMemberDiffKind(): ExpectActualMemberDiff.Kind? = when (this) { ExpectActualCompatibility.Incompatible.CallableKind -> ExpectActualMemberDiff.Kind.NonPrivateCallableAdded ExpectActualCompatibility.Incompatible.ParameterCount -> ExpectActualMemberDiff.Kind.NonPrivateCallableAdded ExpectActualCompatibility.Incompatible.ParameterShape -> ExpectActualMemberDiff.Kind.NonPrivateCallableAdded ExpectActualCompatibility.Incompatible.ParameterTypes -> ExpectActualMemberDiff.Kind.NonPrivateCallableAdded ExpectActualCompatibility.Incompatible.ReturnType -> ExpectActualMemberDiff.Kind.ReturnTypeChangedInOverride ExpectActualCompatibility.Incompatible.FunctionTypeParameterCount -> ExpectActualMemberDiff.Kind.NonPrivateCallableAdded - ExpectActualCompatibility.Incompatible.ClassTypeParameterCount -> null // Not applicable because ExpectActualMemberDiff is about members + ExpectActualCompatibility.Incompatible.ClassTypeParameterCount -> error("Not applicable because ExpectActualMemberDiff is about members") ExpectActualCompatibility.Incompatible.FunctionTypeParameterUpperBounds -> ExpectActualMemberDiff.Kind.NonPrivateCallableAdded - ExpectActualCompatibility.Incompatible.ClassTypeParameterUpperBounds -> null // Not applicable because ExpectActualMemberDiff is about members + ExpectActualCompatibility.Incompatible.ClassTypeParameterUpperBounds -> error("Not applicable because ExpectActualMemberDiff is about members") ExpectActualCompatibility.Incompatible.ActualFunctionWithDefaultParameters -> null // It's not possible to add default parameters in override - ExpectActualCompatibility.Incompatible.ClassKind -> null // Not applicable because ExpectActualMemberDiff is about members - ExpectActualCompatibility.Incompatible.ClassModifiers -> null // Not applicable because ExpectActualMemberDiff is about members - is ExpectActualCompatibility.Incompatible.ClassScopes -> null // Not applicable because ExpectActualMemberDiff is about members - ExpectActualCompatibility.Incompatible.EnumEntries -> null // Not applicable because ExpectActualMemberDiff is about members - ExpectActualCompatibility.Incompatible.FunInterfaceModifier -> null // Not applicable because ExpectActualMemberDiff is about members - ExpectActualCompatibility.Incompatible.FunctionModifiersDifferent -> null // It's not possible to override with different function modifier - ExpectActualCompatibility.Incompatible.FunctionModifiersNotSubset -> null // It's not possible to override with different function modifier + ExpectActualCompatibility.Incompatible.ClassKind -> error("Not applicable because ExpectActualMemberDiff is about members") + ExpectActualCompatibility.Incompatible.ClassModifiers -> error("Not applicable because ExpectActualMemberDiff is about members") + is ExpectActualCompatibility.Incompatible.ClassScopes -> error("Not applicable because ExpectActualMemberDiff is about members") + ExpectActualCompatibility.Incompatible.EnumEntries -> error("Not applicable because ExpectActualMemberDiff is about members") + ExpectActualCompatibility.Incompatible.FunInterfaceModifier -> error("Not applicable because ExpectActualMemberDiff is about members") + ExpectActualCompatibility.Incompatible.FunctionModifiersDifferent -> null // It's not possible to override with different function modifier (suspend) + ExpectActualCompatibility.Incompatible.FunctionModifiersNotSubset -> null // It's not possible to override with different function modifier (infix, inline, operator) ExpectActualCompatibility.Incompatible.Modality -> ExpectActualMemberDiff.Kind.ModalityChangedInOverride ExpectActualCompatibility.Incompatible.ParameterNames -> ExpectActualMemberDiff.Kind.ParameterNameChangedInOverride ExpectActualCompatibility.Incompatible.PropertyConstModifier -> null // const fun can't be overridden ExpectActualCompatibility.Incompatible.PropertyKind -> ExpectActualMemberDiff.Kind.PropertyKindChangedInOverride ExpectActualCompatibility.Incompatible.PropertyLateinitModifier -> ExpectActualMemberDiff.Kind.LateinitChangedInOverride ExpectActualCompatibility.Incompatible.PropertySetterVisibility -> ExpectActualMemberDiff.Kind.SetterVisibilityChangedInOverride - ExpectActualCompatibility.Incompatible.Supertypes -> null // Not applicable because ExpectActualMemberDiff is about members. But related: ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_SUPERTYPES_AS_NON_FINAL_EXPECT_CLASSIFIER + ExpectActualCompatibility.Incompatible.Supertypes -> error("Not applicable because ExpectActualMemberDiff is about members") ExpectActualCompatibility.Incompatible.TypeParameterNames -> ExpectActualMemberDiff.Kind.TypeParameterNamesChangedInOverride ExpectActualCompatibility.Incompatible.TypeParameterReified -> null // inline fun can't be overridden ExpectActualCompatibility.Incompatible.TypeParameterVariance -> null // Members are not allowed to have variance