[FE] Prohibit open val deferred initialization

^KT-57553 Fixed
Review: https://jetbrains.team/p/kt/reviews/9967

Other related tests:
- testUninitializedOrReassignedVariables
- testUseOfPropertiesWithoutPrimary
- @TestMetadata("compiler/testData/diagnostics/tests/secondaryConstructors")
- testAugmentedAssignmentInInitializer
- testInitOpenSetter
- testInitOverrideInConstructorComplex
- testPropertyInitializationOrder
This commit is contained in:
Nikita Bobko
2023-05-01 15:18:51 +02:00
parent 38319c55a8
commit ac40010501
27 changed files with 399 additions and 151 deletions
@@ -1010,8 +1010,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val MUST_BE_INITIALIZED by error<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
val MUST_BE_INITIALIZED_OR_BE_FINAL by error<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
val MUST_BE_INITIALIZED_OR_BE_FINAL_WARNING by warning<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
val MUST_BE_INITIALIZED_OR_BE_ABSTRACT by error<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
val MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT by error<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
val MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT_WARNING by warning<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
val EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT by error<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
val UNNECESSARY_LATEINIT by warning<KtProperty>(PositioningStrategy.LATEINIT_MODIFIER)
@@ -534,8 +534,10 @@ object FirErrors {
val PROPERTY_WITH_NO_TYPE_NO_INITIALIZER by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
val MUST_BE_INITIALIZED by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
val MUST_BE_INITIALIZED_OR_BE_FINAL by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
val MUST_BE_INITIALIZED_OR_BE_FINAL_WARNING by warning0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
val MUST_BE_INITIALIZED_OR_BE_ABSTRACT by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
val MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
val MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT_WARNING by warning0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
val EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
val UNNECESSARY_LATEINIT by warning0<KtProperty>(SourceElementPositioningStrategies.LATEINIT_MODIFIER)
val BACKING_FIELD_IN_INTERFACE by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
@@ -185,12 +185,28 @@ private fun reportMustBeInitialized(
property.getEffectiveModality(containingClass, context.languageVersionSettings) != Modality.FINAL &&
isDefinitelyAssignedInConstructor
val suggestMakingItAbstract = containingClass != null && !property.hasAnyAccessorImplementation
val isOpenValDeferredInitDeprecationWarning =
!context.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitOpenValDeferredInitialization) &&
property.getEffectiveModality(containingClass, context.languageVersionSettings) == Modality.OPEN && property.isVal &&
isDefinitelyAssignedInConstructor
val factory = when {
suggestMakingItFinal && suggestMakingItAbstract -> FirErrors.MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT
suggestMakingItFinal -> FirErrors.MUST_BE_INITIALIZED_OR_BE_FINAL
suggestMakingItAbstract -> FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT
else -> FirErrors.MUST_BE_INITIALIZED
suggestMakingItFinal && suggestMakingItAbstract -> when (isOpenValDeferredInitDeprecationWarning) {
true -> FirErrors.MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT_WARNING
false -> FirErrors.MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT
}
suggestMakingItFinal -> when (isOpenValDeferredInitDeprecationWarning) {
true -> FirErrors.MUST_BE_INITIALIZED_OR_BE_FINAL_WARNING
false -> FirErrors.MUST_BE_INITIALIZED_OR_BE_FINAL
}
suggestMakingItAbstract -> when (isOpenValDeferredInitDeprecationWarning) {
true -> error("Not reachable case. Every \"open val + deferred init\" case that could be made `abstract`, also could be made `final`")
false -> FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT
}
else -> when (isOpenValDeferredInitDeprecationWarning) {
true -> error("Not reachable case. We can always suggest making `open val` property `final`")
false -> FirErrors.MUST_BE_INITIALIZED
}
}
reporter.reportOn(propertySource, factory, context)
}
@@ -338,7 +338,9 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTI_FIELD_VALUE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_BE_FINAL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_BE_FINAL_WARNING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT_WARNING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAMED_ARGUMENTS_NOT_ALLOWED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAMED_PARAMETER_NOT_FOUND
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAME_FOR_AMBIGUOUS_PARAMETER
@@ -1632,8 +1634,10 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(MUST_BE_INITIALIZED, "Property must be initialized")
map.put(MUST_BE_INITIALIZED_OR_BE_FINAL, "Property must be initialized or be final")
map.put(MUST_BE_INITIALIZED_OR_BE_FINAL_WARNING, "Property must be initialized or be final. This warning will become an error in future releases.")
map.put(MUST_BE_INITIALIZED_OR_BE_ABSTRACT, "Property must be initialized or be abstract")
map.put(MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT, "Property must be initialized, be final, or be abstract");
map.put(MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT, "Property must be initialized, be final, or be abstract")
map.put(MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT_WARNING, "Property must be initialized, be final, or be abstract. This warning will become an error in future releases.")
map.put(EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT, "Extension property must have accessors or be abstract")
map.put(UNNECESSARY_LATEINIT, "Lateinit is unnecessary: definitely initialized in constructors")