[FIR] 2/2 Support more wider actual member visibility, if the expect member is effectively final

^KT-61955 Fixed

Introduce LV vs don't introduce LV:

introduce LV:
- K1 IDE and K2 project: IDE accurately shows compiler errors
- K2 IDE and K1 project: There are cases when IDE shows red but in reality it's green

don't introduce LV:
- K1 IDE and K2 project: There are cases when IDE shows red but in reality it's green
- K2 IDE and K1 project: There are cases when IDE shows green but in reality it's red
This commit is contained in:
Nikita Bobko
2023-09-14 20:26:14 +02:00
committed by Space Team
parent e13ebe8474
commit 7b8445f914
13 changed files with 246 additions and 3 deletions
@@ -367,6 +367,36 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt"); runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt");
} }
@Test
@TestMetadata("widerVisibility_expectIsEffectivelyFinal.kt")
public void testWiderVisibility_expectIsEffectivelyFinal() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectIsEffectivelyFinal.kt");
}
@Test
@TestMetadata("widerVisibility_expectIsEffectivelyFinal_fakeOverride.kt")
public void testWiderVisibility_expectIsEffectivelyFinal_fakeOverride() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectIsEffectivelyFinal_fakeOverride.kt");
}
@Test
@TestMetadata("widerVisibility_expectIsEffectivelyFinal_oldLanguageVersion.kt")
public void testWiderVisibility_expectIsEffectivelyFinal_oldLanguageVersion() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectIsEffectivelyFinal_oldLanguageVersion.kt");
}
@Test
@TestMetadata("widerVisibility_expectSetterIsEffectivelyFinal.kt")
public void testWiderVisibility_expectSetterIsEffectivelyFinal() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectSetterIsEffectivelyFinal.kt");
}
@Test
@TestMetadata("widerVisibility_expectSetterIsEffectivelyFinal_fakeOverride.kt")
public void testWiderVisibility_expectSetterIsEffectivelyFinal_fakeOverride() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectSetterIsEffectivelyFinal_fakeOverride.kt");
}
@Nested @Nested
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker") @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -367,6 +367,36 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt"); runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt");
} }
@Test
@TestMetadata("widerVisibility_expectIsEffectivelyFinal.kt")
public void testWiderVisibility_expectIsEffectivelyFinal() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectIsEffectivelyFinal.kt");
}
@Test
@TestMetadata("widerVisibility_expectIsEffectivelyFinal_fakeOverride.kt")
public void testWiderVisibility_expectIsEffectivelyFinal_fakeOverride() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectIsEffectivelyFinal_fakeOverride.kt");
}
@Test
@TestMetadata("widerVisibility_expectIsEffectivelyFinal_oldLanguageVersion.kt")
public void testWiderVisibility_expectIsEffectivelyFinal_oldLanguageVersion() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectIsEffectivelyFinal_oldLanguageVersion.kt");
}
@Test
@TestMetadata("widerVisibility_expectSetterIsEffectivelyFinal.kt")
public void testWiderVisibility_expectSetterIsEffectivelyFinal() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectSetterIsEffectivelyFinal.kt");
}
@Test
@TestMetadata("widerVisibility_expectSetterIsEffectivelyFinal_fakeOverride.kt")
public void testWiderVisibility_expectSetterIsEffectivelyFinal_fakeOverride() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectSetterIsEffectivelyFinal_fakeOverride.kt");
}
@Nested @Nested
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker") @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.resolve.calls.mpp package org.jetbrains.kotlin.resolve.calls.mpp
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
@@ -360,6 +361,7 @@ object AbstractExpectActualChecker {
if (!areCompatibleCallableVisibilities( if (!areCompatibleCallableVisibilities(
expectDeclaration.visibility, expectDeclaration.visibility,
expectModality, expectModality,
expectContainingClass?.modality,
actualDeclaration.visibility, actualDeclaration.visibility,
languageVersionSettings languageVersionSettings
) )
@@ -404,7 +406,7 @@ object AbstractExpectActualChecker {
getFunctionsIncompatibility(expectDeclaration, actualDeclaration)?.let { return it } getFunctionsIncompatibility(expectDeclaration, actualDeclaration)?.let { return it }
expectDeclaration is PropertySymbolMarker && actualDeclaration is PropertySymbolMarker -> expectDeclaration is PropertySymbolMarker && actualDeclaration is PropertySymbolMarker ->
getPropertiesIncompatibility(expectDeclaration, actualDeclaration, languageVersionSettings)?.let { return it } getPropertiesIncompatibility(expectDeclaration, actualDeclaration, expectContainingClass, languageVersionSettings)?.let { return it }
expectDeclaration is EnumEntrySymbolMarker && actualDeclaration is EnumEntrySymbolMarker -> { expectDeclaration is EnumEntrySymbolMarker && actualDeclaration is EnumEntrySymbolMarker -> {
// do nothing, entries are matched only by name // do nothing, entries are matched only by name
@@ -465,11 +467,17 @@ object AbstractExpectActualChecker {
private fun areCompatibleCallableVisibilities( private fun areCompatibleCallableVisibilities(
expectVisibility: Visibility, expectVisibility: Visibility,
expectModality: Modality?, expectModality: Modality?,
expectContainingClassModality: Modality?,
actualVisibility: Visibility, actualVisibility: Visibility,
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
): Boolean { ): Boolean {
val compare = Visibilities.compare(expectVisibility, actualVisibility) val compare = Visibilities.compare(expectVisibility, actualVisibility)
return if (expectModality != Modality.FINAL) { val effectiveModality =
when (languageVersionSettings.supportsFeature(LanguageFeature.SupportEffectivelyFinalInExpectActualVisibilityCheck)) {
true -> effectiveModality(expectModality, expectContainingClassModality)
false -> expectModality
}
return if (effectiveModality != Modality.FINAL) {
// For overridable declarations visibility should match precisely, see KT-19664 // For overridable declarations visibility should match precisely, see KT-19664
compare == 0 compare == 0
} else { } else {
@@ -536,13 +544,14 @@ object AbstractExpectActualChecker {
private fun getPropertiesIncompatibility( private fun getPropertiesIncompatibility(
expected: PropertySymbolMarker, expected: PropertySymbolMarker,
actual: PropertySymbolMarker, actual: PropertySymbolMarker,
expectContainingClass: RegularClassSymbolMarker?,
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
): ExpectActualCheckingCompatibility.Incompatible<*>? { ): ExpectActualCheckingCompatibility.Incompatible<*>? {
return when { return when {
!equalBy(expected, actual) { p -> p.isVar } -> ExpectActualCheckingCompatibility.PropertyKind !equalBy(expected, actual) { p -> p.isVar } -> ExpectActualCheckingCompatibility.PropertyKind
!equalBy(expected, actual) { p -> p.isLateinit } -> ExpectActualCheckingCompatibility.PropertyLateinitModifier !equalBy(expected, actual) { p -> p.isLateinit } -> ExpectActualCheckingCompatibility.PropertyLateinitModifier
expected.isConst && !actual.isConst -> ExpectActualCheckingCompatibility.PropertyConstModifier expected.isConst && !actual.isConst -> ExpectActualCheckingCompatibility.PropertyConstModifier
!arePropertySettersWithCompatibleVisibilities(expected, actual, languageVersionSettings) -> !arePropertySettersWithCompatibleVisibilities(expected, actual, expectContainingClass, languageVersionSettings) ->
ExpectActualCheckingCompatibility.PropertySetterVisibility ExpectActualCheckingCompatibility.PropertySetterVisibility
else -> null else -> null
} }
@@ -552,6 +561,7 @@ object AbstractExpectActualChecker {
private fun arePropertySettersWithCompatibleVisibilities( private fun arePropertySettersWithCompatibleVisibilities(
expected: PropertySymbolMarker, expected: PropertySymbolMarker,
actual: PropertySymbolMarker, actual: PropertySymbolMarker,
expectContainingClass: RegularClassSymbolMarker?,
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
): Boolean { ): Boolean {
val expectedSetter = expected.setter ?: return true val expectedSetter = expected.setter ?: return true
@@ -559,6 +569,7 @@ object AbstractExpectActualChecker {
return areCompatibleCallableVisibilities( return areCompatibleCallableVisibilities(
expectedSetter.visibility, expectedSetter.visibility,
expectedSetter.modality, expectedSetter.modality,
expectContainingClass?.modality,
actualSetter.visibility, actualSetter.visibility,
languageVersionSettings languageVersionSettings
) )
@@ -0,0 +1,17 @@
// MODULE: m1-common
// FILE: common.kt
open class Base {
internal open fun foo() {}
}
expect class Foo : Base {
override fun foo()
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class Foo : Base() {
public actual override fun foo() {
}
}
@@ -0,0 +1,17 @@
// MODULE: m1-common
// FILE: common.kt
open class Base {
internal open fun foo() {}
}
expect class Foo : Base {
override fun foo()
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class Foo : Base() {
<!ACTUAL_WITHOUT_EXPECT!>public<!> actual override fun foo() {
}
}
@@ -0,0 +1,16 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
open class Base {
protected open fun foo() {}
}
expect class Foo : Base
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class Foo : Base() {
public override fun foo() {
}
}
@@ -0,0 +1,18 @@
// LANGUAGE: -SupportEffectivelyFinalInExpectActualVisibilityCheck
// MODULE: m1-common
// FILE: common.kt
open class Base {
internal open fun foo() {}
}
<!EXPECT_ACTUAL_INCOMPATIBILITY{JVM}!>expect class Foo : Base {
<!EXPECT_ACTUAL_INCOMPATIBILITY{JVM}!>override fun foo()<!>
}<!>
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class Foo : Base() {
public actual override fun <!ACTUAL_WITHOUT_EXPECT!>foo<!>() {
}
}
@@ -0,0 +1,18 @@
// LANGUAGE: -SupportEffectivelyFinalInExpectActualVisibilityCheck
// MODULE: m1-common
// FILE: common.kt
open class Base {
internal open fun foo() {}
}
expect class Foo : Base {
override fun foo()
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class Foo : Base() {
<!ACTUAL_WITHOUT_EXPECT!>public<!> actual override fun foo() {
}
}
@@ -0,0 +1,19 @@
// MODULE: m1-common
// FILE: common.kt
open class Base {
open var foo: Int = 2
internal set
}
expect class Foo : Base {
override var foo: Int
internal set
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class Foo : Base() {
actual override var foo: Int = 2
public set
}
@@ -0,0 +1,19 @@
// MODULE: m1-common
// FILE: common.kt
open class Base {
open var foo: Int = 2
internal set
}
expect class Foo : Base {
override var foo: Int
internal set
}
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class Foo : Base() {
actual override var foo: Int = 2
<!ACTUAL_WITHOUT_EXPECT!>public<!> set
}
@@ -0,0 +1,17 @@
// FIR_IDENTICAL
// MODULE: m1-common
// FILE: common.kt
open class Base {
open var foo: Int = 2
protected set
}
expect class Foo : Base
// MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt
actual class Foo : Base() {
override var foo: Int = 2
public set
}
@@ -23734,6 +23734,36 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt"); runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt");
} }
@Test
@TestMetadata("widerVisibility_expectIsEffectivelyFinal.kt")
public void testWiderVisibility_expectIsEffectivelyFinal() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectIsEffectivelyFinal.kt");
}
@Test
@TestMetadata("widerVisibility_expectIsEffectivelyFinal_fakeOverride.kt")
public void testWiderVisibility_expectIsEffectivelyFinal_fakeOverride() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectIsEffectivelyFinal_fakeOverride.kt");
}
@Test
@TestMetadata("widerVisibility_expectIsEffectivelyFinal_oldLanguageVersion.kt")
public void testWiderVisibility_expectIsEffectivelyFinal_oldLanguageVersion() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectIsEffectivelyFinal_oldLanguageVersion.kt");
}
@Test
@TestMetadata("widerVisibility_expectSetterIsEffectivelyFinal.kt")
public void testWiderVisibility_expectSetterIsEffectivelyFinal() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectSetterIsEffectivelyFinal.kt");
}
@Test
@TestMetadata("widerVisibility_expectSetterIsEffectivelyFinal_fakeOverride.kt")
public void testWiderVisibility_expectSetterIsEffectivelyFinal_fakeOverride() throws Exception {
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibility_expectSetterIsEffectivelyFinal_fakeOverride.kt");
}
@Nested @Nested
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker") @TestMetadata("compiler/testData/diagnostics/tests/multiplatform/actualClassifierMustHasTheSameMembersAsNonFinalExpectClassifierChecker")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@@ -303,6 +303,7 @@ enum class LanguageFeature(
KeepNullabilityWhenApproximatingLocalType(KOTLIN_2_0, kind = BUG_FIX), // KT-53982 KeepNullabilityWhenApproximatingLocalType(KOTLIN_2_0, kind = BUG_FIX), // KT-53982
ProhibitAccessToInvisibleSetterFromDerivedClass(KOTLIN_2_0, kind = BUG_FIX), // KT-56662 ProhibitAccessToInvisibleSetterFromDerivedClass(KOTLIN_2_0, kind = BUG_FIX), // KT-56662
ProhibitOpenValDeferredInitialization(KOTLIN_2_0, kind = BUG_FIX), // KT-57553 ProhibitOpenValDeferredInitialization(KOTLIN_2_0, kind = BUG_FIX), // KT-57553
SupportEffectivelyFinalInExpectActualVisibilityCheck(KOTLIN_2_0, kind = BUG_FIX), // KT-61955
ProhibitMissedMustBeInitializedWhenThereIsNoPrimaryConstructor(KOTLIN_2_0, kind = BUG_FIX), // KT-58472 ProhibitMissedMustBeInitializedWhenThereIsNoPrimaryConstructor(KOTLIN_2_0, kind = BUG_FIX), // KT-58472
MangleCallsToJavaMethodsWithValueClasses(KOTLIN_2_0, kind = OTHER), // KT-55945 MangleCallsToJavaMethodsWithValueClasses(KOTLIN_2_0, kind = OTHER), // KT-55945
ForbidInferringTypeVariablesIntoEmptyIntersection(KOTLIN_2_0, kind = BUG_FIX), // KT-51221 ForbidInferringTypeVariablesIntoEmptyIntersection(KOTLIN_2_0, kind = BUG_FIX), // KT-51221