diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt index a2e0c36c68e..81f23a8e1f9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt @@ -34,7 +34,6 @@ import org.jetbrains.kotlin.cfg.pseudocodeTraverser.* import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.impl.referencedProperty import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticFactory import org.jetbrains.kotlin.diagnostics.Errors @@ -400,18 +399,6 @@ class ControlFlowInformationProvider private constructor( varWithValReassignErrorGenerated: MutableCollection ): Boolean { val variableDescriptor = ctxt.variableDescriptor - val propertyDescriptor = variableDescriptor?.referencedProperty - if (KtPsiUtil.isBackingFieldReference(variableDescriptor) && propertyDescriptor != null) { - val accessor = getParentOfType(expression, KtPropertyAccessor::class.java) - if (accessor != null) { - val accessorDescriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, accessor) - if (propertyDescriptor.getter === accessorDescriptor) { - //val can be reassigned through backing field inside its own getter - return false - } - } - } - val mayBeInitializedNotHere = ctxt.enterInitState?.mayBeInitialized() ?: false val hasBackingField = (variableDescriptor as? PropertyDescriptor)?.let { trace.get(BindingContext.BACKING_FIELD_REQUIRED, it) @@ -469,7 +456,12 @@ class ControlFlowInformationProvider private constructor( } } else { - report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor), ctxt) + if (KtPsiUtil.isBackingFieldReference(variableDescriptor)) { + report(Errors.VAL_REASSIGNMENT_VIA_BACKING_FIELD.on(expression, variableDescriptor), ctxt) + } + else { + report(Errors.VAL_REASSIGNMENT.on(expression, variableDescriptor), ctxt) + } } } if (isThisOrNoDispatchReceiver) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index abb11f97f0c..b41ab2ff7ea 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -761,6 +761,7 @@ public interface Errors { DiagnosticFactory0 UNUSED_LAMBDA_EXPRESSION = DiagnosticFactory0.create(WARNING); DiagnosticFactory1 VAL_REASSIGNMENT = DiagnosticFactory1.create(ERROR); + DiagnosticFactory1 VAL_REASSIGNMENT_VIA_BACKING_FIELD = DiagnosticFactory1.create(WARNING); DiagnosticFactory1 CAPTURED_VAL_INITIALIZATION = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 CAPTURED_MEMBER_VAL_INITIALIZATION = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 SETTER_PROJECTED_OUT = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index d1b7b74fe61..e6bb6b7ed85 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -299,6 +299,7 @@ public class DefaultErrorMessages { MAP.put(UNUSED_LAMBDA_EXPRESSION, "The lambda expression is unused. If you mean a block, you can use 'run { ... }'"); MAP.put(VAL_REASSIGNMENT, "Val cannot be reassigned", NAME); + MAP.put(VAL_REASSIGNMENT_VIA_BACKING_FIELD, "Val cannot be reassigned via backing field", NAME); MAP.put(CAPTURED_VAL_INITIALIZATION, "Captured values initialization is forbidden due to possible reassignment", NAME); MAP.put(CAPTURED_MEMBER_VAL_INITIALIZATION, "Captured member values initialization is forbidden due to possible reassignment", NAME); MAP.put(SETTER_PROJECTED_OUT, "Setter for ''{0}'' is removed by type projection", NAME); diff --git a/compiler/testData/diagnostics/tests/backingField/FieldReassignment.kt b/compiler/testData/diagnostics/tests/backingField/FieldReassignment.kt index 755979ab00d..1c37a864b4d 100644 --- a/compiler/testData/diagnostics/tests/backingField/FieldReassignment.kt +++ b/compiler/testData/diagnostics/tests/backingField/FieldReassignment.kt @@ -1,5 +1,5 @@ val my: Int = 1 get() { - field++ + field++ return field } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/backingFieldInsideGetter.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/backingFieldInsideGetter.kt index e37236bc0be..2d0093d4c2f 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/backingFieldInsideGetter.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/backingFieldInsideGetter.kt @@ -5,7 +5,7 @@ import java.util.HashSet val a: MutableSet? = null get() { if (a == null) { - field = HashSet() + field = HashSet() } return a } @@ -14,7 +14,7 @@ class R { val b: String? = null get() { if (b == null) { - field = "b" + field = "b" } return b }