diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index bc4dd31022b..504fca960bb 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -1216,9 +1216,14 @@ abstract class FirDataFlowAnalyzer( fun exitVariableAssignment(assignment: FirVariableAssignment) { val node = graphBuilder.exitVariableAssignment(assignment).mergeIncomingFlow() val property = assignment.lValue.resolvedSymbol?.fir as? FirProperty ?: return - // TODO: add unstable smartcast - if (property.isLocal || !property.isVar) { + if (property.isLocal || property.isVal) { exitVariableInitialization(node, assignment.rValue, property, assignment, hasExplicitType = false) + } else { + // TODO: add unstable smartcast for non-local var + val variable = variableStorage.getRealVariableWithoutUnwrappingAlias(node.flow, property.symbol, assignment) + if (variable != null) { + logicSystem.removeAllAboutVariable(node.flow, variable) + } } processConditionalContract(assignment) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirLocalVariableAssignmentAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirLocalVariableAssignmentAnalyzer.kt index 8f83e10f155..8f899738464 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirLocalVariableAssignmentAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirLocalVariableAssignmentAnalyzer.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.utils.referredPropertySymbol import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.references.FirNamedReference +import org.jetbrains.kotlin.fir.references.FirReference import org.jetbrains.kotlin.fir.resolve.dfa.FirLocalVariableAssignmentAnalyzer.Companion.MiniFlow.Companion.join import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.visitors.FirVisitor @@ -369,23 +370,21 @@ internal class FirLocalVariableAssignmentAnalyzer( override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: MiniCfgData) { super.visitVariableAssignment(variableAssignment, data) - val flow = data.flow ?: return - val name = (variableAssignment.lValue as? FirNamedReference)?.name ?: return - flow.recordAssignment(name, data) + if (variableAssignment.explicitReceiver != null) return + data.recordAssignment(variableAssignment.lValue) } override fun visitAssignmentOperatorStatement(assignmentOperatorStatement: FirAssignmentOperatorStatement, data: MiniCfgData) { super.visitAssignmentOperatorStatement(assignmentOperatorStatement, data) - val flow = data.flow ?: return val lhs = assignmentOperatorStatement.leftArgument as? FirQualifiedAccessExpression ?: return if (lhs.explicitReceiver != null) return - val name = (lhs.calleeReference as? FirNamedReference)?.name ?: return - flow.recordAssignment(name, data) + data.recordAssignment(lhs.calleeReference) } - fun MiniFlow.recordAssignment(name: Name, data: MiniCfgData) { - val property = data.resolveLocalVariable(name) ?: return - recordAssignment(property, mutableSetOf()) + fun MiniCfgData.recordAssignment(reference: FirReference) { + val name = (reference as? FirNamedReference)?.name ?: return + val property = resolveLocalVariable(name) ?: return + flow?.recordAssignment(property, mutableSetOf()) } private fun MiniFlow.recordAssignment(property: FirProperty, visited: MutableSet) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PreliminaryLoopVisitor.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PreliminaryLoopVisitor.kt index 9bdbd01cf08..bfeb29ab161 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PreliminaryLoopVisitor.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PreliminaryLoopVisitor.kt @@ -44,6 +44,10 @@ class PreliminaryLoopVisitor { override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: FirStatement?) { if (variableAssignment.source?.kind == KtFakeSourceElementKind.DesugaredIncrementOrDecrement) return + // Only care about local variable assignments, which never have explicit receivers. If this is a `var` + // property assignment, the smart cast will be unstable anyway. + if (variableAssignment.explicitReceiver != null) return + val reference = variableAssignment.lValue as? FirNamedReference if (reference != null) { requireNotNull(data) diff --git a/compiler/testData/diagnostics/tests/smartCasts/implicitThisOrLocalVar.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/implicitThisOrLocalVar.fir.kt index 6bbb354caf5..7b58f63e906 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/implicitThisOrLocalVar.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/implicitThisOrLocalVar.fir.kt @@ -10,7 +10,7 @@ fun Box.test() { other.item = null take(item) this.item = null - take(item) + take(item) } } @@ -18,7 +18,7 @@ fun Box.test() { myRun { if (item != null) { this.item = null - take(item) + take(item) } } }