From 9a65dcb664c9e2e1f2829247e11064baa79d96f7 Mon Sep 17 00:00:00 2001 From: Nikita Bobko Date: Wed, 10 May 2023 16:00:54 +0200 Subject: [PATCH] MUST_BE_INITIALIZED: take into account containingDeclaration's modality ^KT-58587 Fixed Review: https://jetbrains.team/p/kt/reviews/10136 This commit is important in scope of KT-57553. It makes the migration more smooth. Other related tests: - testUninitializedOrReassignedVariables - testAugmentedAssignmentInInitializer --- ...CompilerTestFE10TestdataTestGenerated.java | 12 +++++ ...sticCompilerFE10TestDataTestGenerated.java | 12 +++++ ...eeOldFrontendDiagnosticsTestGenerated.java | 12 +++++ ...siOldFrontendDiagnosticsTestGenerated.java | 12 +++++ .../kotlin/fir/backend/IrBuiltInsOverFir.kt | 45 ++++++++++++------- .../cfg/ControlFlowInformationProviderImpl.kt | 9 +++- ...ustBeInitializedEffectivelyFinalOff.fir.kt | 12 +++++ .../MustBeInitializedEffectivelyFinalOff.kt | 12 +++++ .../MustBeInitializedEffectivelyFinalOn.kt | 13 ++++++ .../test/runners/DiagnosticTestGenerated.java | 12 +++++ .../kotlin/config/LanguageVersionSettings.kt | 1 + 11 files changed, 136 insertions(+), 16 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOff.fir.kt create mode 100644 compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOff.kt create mode 100644 compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOn.kt diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java index 4a9665993a1..40cf8873b85 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosticCompilerTestFE10TestdataTestGenerated.java @@ -2948,6 +2948,18 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia runTest("compiler/testData/diagnostics/tests/backingField/LocalDeclarations.kt"); } + @Test + @TestMetadata("MustBeInitializedEffectivelyFinalOff.kt") + public void testMustBeInitializedEffectivelyFinalOff() throws Exception { + runTest("compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOff.kt"); + } + + @Test + @TestMetadata("MustBeInitializedEffectivelyFinalOn.kt") + public void testMustBeInitializedEffectivelyFinalOn() throws Exception { + runTest("compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOn.kt"); + } + @Test @TestMetadata("SetterWithExplicitType.kt") public void testSetterWithExplicitType() throws Exception { diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java index 8fe1708beda..0fb6f544c5f 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated.java @@ -2948,6 +2948,18 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated runTest("compiler/testData/diagnostics/tests/backingField/LocalDeclarations.kt"); } + @Test + @TestMetadata("MustBeInitializedEffectivelyFinalOff.kt") + public void testMustBeInitializedEffectivelyFinalOff() throws Exception { + runTest("compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOff.kt"); + } + + @Test + @TestMetadata("MustBeInitializedEffectivelyFinalOn.kt") + public void testMustBeInitializedEffectivelyFinalOn() throws Exception { + runTest("compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOn.kt"); + } + @Test @TestMetadata("SetterWithExplicitType.kt") public void testSetterWithExplicitType() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java index 46992b6f0a3..35899c54390 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsTestGenerated.java @@ -2948,6 +2948,18 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir runTest("compiler/testData/diagnostics/tests/backingField/LocalDeclarations.kt"); } + @Test + @TestMetadata("MustBeInitializedEffectivelyFinalOff.kt") + public void testMustBeInitializedEffectivelyFinalOff() throws Exception { + runTest("compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOff.kt"); + } + + @Test + @TestMetadata("MustBeInitializedEffectivelyFinalOn.kt") + public void testMustBeInitializedEffectivelyFinalOn() throws Exception { + runTest("compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOn.kt"); + } + @Test @TestMetadata("SetterWithExplicitType.kt") public void testSetterWithExplicitType() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java index 9e784605098..2f9596eced8 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirPsiOldFrontendDiagnosticsTestGenerated.java @@ -2954,6 +2954,18 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia runTest("compiler/testData/diagnostics/tests/backingField/LocalDeclarations.kt"); } + @Test + @TestMetadata("MustBeInitializedEffectivelyFinalOff.kt") + public void testMustBeInitializedEffectivelyFinalOff() throws Exception { + runTest("compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOff.kt"); + } + + @Test + @TestMetadata("MustBeInitializedEffectivelyFinalOn.kt") + public void testMustBeInitializedEffectivelyFinalOn() throws Exception { + runTest("compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOn.kt"); + } + @Test @TestMetadata("SetterWithExplicitType.kt") public void testSetterWithExplicitType() throws Exception { diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt index d859d577ca3..e9953f50c81 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/IrBuiltInsOverFir.kt @@ -372,18 +372,29 @@ class IrBuiltInsOverFir( override val ieee754equalsFunByOperandType: MutableMap get() = _ieee754equalsFunByOperandType - override lateinit var eqeqeqSymbol: IrSimpleFunctionSymbol private set - override lateinit var eqeqSymbol: IrSimpleFunctionSymbol private set - override lateinit var throwCceSymbol: IrSimpleFunctionSymbol private set - override lateinit var throwIseSymbol: IrSimpleFunctionSymbol private set - override lateinit var andandSymbol: IrSimpleFunctionSymbol private set - override lateinit var ororSymbol: IrSimpleFunctionSymbol private set - override lateinit var noWhenBranchMatchedExceptionSymbol: IrSimpleFunctionSymbol private set - override lateinit var illegalArgumentExceptionSymbol: IrSimpleFunctionSymbol private set - override lateinit var dataClassArrayMemberHashCodeSymbol: IrSimpleFunctionSymbol private set - override lateinit var dataClassArrayMemberToStringSymbol: IrSimpleFunctionSymbol private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var eqeqeqSymbol: IrSimpleFunctionSymbol private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var eqeqSymbol: IrSimpleFunctionSymbol private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var throwCceSymbol: IrSimpleFunctionSymbol private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var throwIseSymbol: IrSimpleFunctionSymbol private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var andandSymbol: IrSimpleFunctionSymbol private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var ororSymbol: IrSimpleFunctionSymbol private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var noWhenBranchMatchedExceptionSymbol: IrSimpleFunctionSymbol private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var illegalArgumentExceptionSymbol: IrSimpleFunctionSymbol private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var dataClassArrayMemberHashCodeSymbol: IrSimpleFunctionSymbol private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var dataClassArrayMemberToStringSymbol: IrSimpleFunctionSymbol private set - override lateinit var checkNotNullSymbol: IrSimpleFunctionSymbol private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var checkNotNullSymbol: IrSimpleFunctionSymbol private set override val arrayOfNulls: IrSimpleFunctionSymbol by lazy { findFunctions(kotlinPackage, Name.identifier("arrayOfNulls")).first { it.owner.dispatchReceiverParameter == null && it.owner.valueParameters.size == 1 && @@ -394,10 +405,14 @@ class IrBuiltInsOverFir( override val linkageErrorSymbol: IrSimpleFunctionSymbol get() = TODO("Not yet implemented") - override lateinit var lessFunByOperandType: Map private set - override lateinit var lessOrEqualFunByOperandType: Map private set - override lateinit var greaterOrEqualFunByOperandType: Map private set - override lateinit var greaterFunByOperandType: Map private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var lessFunByOperandType: Map private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var lessOrEqualFunByOperandType: Map private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var greaterOrEqualFunByOperandType: Map private set + @Suppress("RedundantModalityModifier") // Explicit `final` keyword can be dropped after bootstrap update + final override var greaterFunByOperandType: Map private set init { with(this.operatorsPackageFragment) { diff --git a/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProviderImpl.kt b/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProviderImpl.kt index 0eb4d7a0ecf..a5e68778d11 100644 --- a/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProviderImpl.kt +++ b/compiler/frontend/cfg/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProviderImpl.kt @@ -628,7 +628,7 @@ class ControlFlowInformationProviderImpl private constructor( val property = DescriptorToSourceUtils.descriptorToDeclaration(variableDescriptor) as? KtProperty ?: throw AssertionError("$variableDescriptor is not related to KtProperty") val setter = property.setter - if (variableDescriptor.modality == Modality.FINAL && (setter == null || !setter.hasBody())) { + if (variableDescriptor.getEffectiveModality(languageVersionSettings) == Modality.FINAL && (setter == null || !setter.hasBody())) { return false } @@ -1472,3 +1472,10 @@ class ControlFlowInformationProviderImpl private constructor( return result } } + +private fun PropertyDescriptor.getEffectiveModality(languageVersionSettings: LanguageVersionSettings): Modality = + when (languageVersionSettings.supportsFeature(LanguageFeature.TakeIntoAccountEffectivelyFinalInMustBeInitializedCheck) && + modality == Modality.OPEN && (containingDeclaration as? ClassDescriptor)?.modality == Modality.FINAL) { + true -> Modality.FINAL + false -> modality + } diff --git a/compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOff.fir.kt b/compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOff.fir.kt new file mode 100644 index 00000000000..c55f56e88d5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOff.fir.kt @@ -0,0 +1,12 @@ +// !LANGUAGE:-TakeIntoAccountEffectivelyFinalInMustBeInitializedCheck +open class Base { + open var x: String = "" +} + +class Foo : Base() { + override var x: String + + init { + x = "" + } +} diff --git a/compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOff.kt b/compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOff.kt new file mode 100644 index 00000000000..1e91d1fa62f --- /dev/null +++ b/compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOff.kt @@ -0,0 +1,12 @@ +// !LANGUAGE:-TakeIntoAccountEffectivelyFinalInMustBeInitializedCheck +open class Base { + open var x: String = "" +} + +class Foo : Base() { + override var x: String + + init { + x = "" + } +} diff --git a/compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOn.kt b/compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOn.kt new file mode 100644 index 00000000000..04bd3cccc5d --- /dev/null +++ b/compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOn.kt @@ -0,0 +1,13 @@ +// FIR_IDENTICAL +// !LANGUAGE:+TakeIntoAccountEffectivelyFinalInMustBeInitializedCheck +open class Base { + open var x: String = "" +} + +class Foo : Base() { + override var x: String + + init { + x = "" + } +} 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 b0512916469..3e04a634204 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 @@ -2954,6 +2954,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/backingField/LocalDeclarations.kt"); } + @Test + @TestMetadata("MustBeInitializedEffectivelyFinalOff.kt") + public void testMustBeInitializedEffectivelyFinalOff() throws Exception { + runTest("compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOff.kt"); + } + + @Test + @TestMetadata("MustBeInitializedEffectivelyFinalOn.kt") + public void testMustBeInitializedEffectivelyFinalOn() throws Exception { + runTest("compiler/testData/diagnostics/tests/backingField/MustBeInitializedEffectivelyFinalOn.kt"); + } + @Test @TestMetadata("SetterWithExplicitType.kt") public void testSetterWithExplicitType() throws Exception { diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index e83a7b7a07c..75487e5d187 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -275,6 +275,7 @@ enum class LanguageFeature( RefineTypeCheckingOnAssignmentsToJavaFields(KOTLIN_1_9, kind = BUG_FIX), // KT-46727 ValueClassesSecondaryConstructorWithBody(sinceVersion = KOTLIN_1_9, kind = UNSTABLE_FEATURE), // KT-55333 NativeJsProhibitLateinitIsInitializedIntrinsicWithoutPrivateAccess(KOTLIN_1_9, kind = BUG_FIX), // KT-27002 + TakeIntoAccountEffectivelyFinalInMustBeInitializedCheck(KOTLIN_1_9, kind = OTHER), // KT-58587 // End of 1.* language features --------------------------------------------------