[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:
-1
@@ -619,7 +619,6 @@ class ControlFlowInformationProviderImpl private constructor(
|
||||
if (variableDescriptor !is PropertyDescriptor
|
||||
|| ctxt.enterInitState?.mayBeInitialized() == true
|
||||
|| ctxt.exitInitState?.mayBeInitialized() != true
|
||||
|| !variableDescriptor.isVar
|
||||
|| trace.get(BACKING_FIELD_REQUIRED, variableDescriptor) != true
|
||||
) {
|
||||
return false
|
||||
|
||||
@@ -674,8 +674,11 @@ public interface Errors {
|
||||
|
||||
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED_OR_BE_FINAL = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED_OR_BE_FINAL_WARNING = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED_OR_BE_ABSTRACT = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT_WARNING = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE);
|
||||
|
||||
DiagnosticFactory0<KtProperty> EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT =
|
||||
DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtProperty> UNNECESSARY_LATEINIT = DiagnosticFactory0.create(WARNING, LATEINIT_MODIFIER);
|
||||
|
||||
+4
@@ -305,10 +305,14 @@ public class DefaultErrorMessages {
|
||||
MAP.put(PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY, "Private setters are not allowed for abstract properties");
|
||||
MAP.put(PRIVATE_SETTER_FOR_OPEN_PROPERTY, "Private setters are not allowed for open properties");
|
||||
MAP.put(BACKING_FIELD_IN_INTERFACE, "Property in an interface cannot have a backing field");
|
||||
|
||||
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_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");
|
||||
MAP.put(PROPERTY_INITIALIZER_IN_INTERFACE, "Property initializers are not allowed in interfaces");
|
||||
|
||||
@@ -775,7 +775,14 @@ class DeclarationsChecker(
|
||||
if (propertyDescriptor.extensionReceiverParameter != null && !hasAnyAccessorImplementation) {
|
||||
trace.report(EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT.on(property))
|
||||
} else if (diagnosticSuppressor.shouldReportNoBody(propertyDescriptor)) {
|
||||
reportMustBeInitialized(propertyDescriptor, containingDeclaration, hasAnyAccessorImplementation, property, trace)
|
||||
reportMustBeInitialized(
|
||||
propertyDescriptor,
|
||||
containingDeclaration,
|
||||
hasAnyAccessorImplementation,
|
||||
property,
|
||||
languageVersionSettings,
|
||||
trace
|
||||
)
|
||||
}
|
||||
} else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) {
|
||||
trace.report(
|
||||
@@ -804,6 +811,7 @@ class DeclarationsChecker(
|
||||
containingDeclaration: DeclarationDescriptor,
|
||||
hasAnyAccessorImplementation: Boolean,
|
||||
property: KtProperty,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
trace: BindingTrace,
|
||||
) {
|
||||
check(propertyDescriptor.getEffectiveModality(languageVersionSettings) != Modality.ABSTRACT) {
|
||||
@@ -814,13 +822,31 @@ class DeclarationsChecker(
|
||||
propertyDescriptor.getEffectiveModality(languageVersionSettings) != Modality.FINAL &&
|
||||
trace.bindingContext.get(IS_DEFINITELY_NOT_ASSIGNED_IN_CONSTRUCTOR, propertyDescriptor) == false
|
||||
val suggestMakingItAbstract = containingDeclaration is ClassDescriptor && !hasAnyAccessorImplementation
|
||||
val isOpenValDeferredInitDeprecationWarning =
|
||||
!languageVersionSettings.supportsFeature(LanguageFeature.ProhibitOpenValDeferredInitialization) &&
|
||||
propertyDescriptor.getEffectiveModality(languageVersionSettings) == Modality.OPEN &&
|
||||
!propertyDescriptor.isVar &&
|
||||
trace.bindingContext.get(IS_DEFINITELY_NOT_ASSIGNED_IN_CONSTRUCTOR, propertyDescriptor) == false
|
||||
|
||||
when {
|
||||
suggestMakingItFinal && suggestMakingItAbstract -> trace.report(MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT.on(property))
|
||||
suggestMakingItFinal -> trace.report(MUST_BE_INITIALIZED_OR_BE_FINAL.on(property))
|
||||
suggestMakingItAbstract -> trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property))
|
||||
else -> trace.report(MUST_BE_INITIALIZED.on(property))
|
||||
val factory = when {
|
||||
suggestMakingItFinal && suggestMakingItAbstract -> when (isOpenValDeferredInitDeprecationWarning) {
|
||||
true -> MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT_WARNING
|
||||
false -> MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT
|
||||
}
|
||||
suggestMakingItFinal -> when (isOpenValDeferredInitDeprecationWarning) {
|
||||
true -> MUST_BE_INITIALIZED_OR_BE_FINAL_WARNING
|
||||
false -> 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 -> MUST_BE_INITIALIZED_OR_BE_ABSTRACT
|
||||
}
|
||||
else -> when (isOpenValDeferredInitDeprecationWarning) {
|
||||
true -> error("Not reachable case. We can always suggest making `open val` property `final`")
|
||||
false -> MUST_BE_INITIALIZED
|
||||
}
|
||||
}
|
||||
trace.report(factory.on(property))
|
||||
}
|
||||
|
||||
private fun noExplicitTypeOrGetterType(property: KtProperty) =
|
||||
|
||||
Reference in New Issue
Block a user