[FIR] Unwrap smartcast on dispatch receiver in CFA for class initialization

^KT-56863 Fixed
This commit is contained in:
Dmitriy Novozhilov
2023-03-01 13:26:57 +02:00
committed by Space Team
parent bb368bd191
commit ae07d0e9ce
9 changed files with 59 additions and 7 deletions
@@ -1212,6 +1212,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
public void testReassignOfNonMemberProperty_lateInitialization() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/cfa/reassignOfNonMemberProperty_lateInitialization.kt");
}
@Test
@TestMetadata("smartcastOnThisDuringClassInitialization.kt")
public void testSmartcastOnThisDuringClassInitialization() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/cfa/smartcastOnThisDuringClassInitialization.kt");
}
}
@Nested
@@ -1045,6 +1045,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
public void testReassignOfNonMemberProperty_lateInitialization() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/cfa/reassignOfNonMemberProperty_lateInitialization.kt");
}
@TestMetadata("smartcastOnThisDuringClassInitialization.kt")
public void testSmartcastOnThisDuringClassInitialization() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/cfa/smartcastOnThisDuringClassInitialization.kt");
}
}
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfg")
@@ -0,0 +1,17 @@
FILE: smartcastOnThisDuringClassInitialization.kt
public abstract interface I : R|kotlin/Any| {
}
public open class Some : R|kotlin/Any| {
public constructor(): R|Some| {
super<R|kotlin/Any|>()
}
public final val x: R|kotlin/Int|
public get(): R|kotlin/Int|
init {
(this@R|/Some| as R|I|)
this@R|/Some|.R|/Some.x| = Int(1)
}
}
@@ -0,0 +1,11 @@
// ISSUE: KT-56863
interface I
open class Some {
val x: Int
init {
this as I
x = 1
}
}
@@ -1212,6 +1212,12 @@ public class FirLightTreeDiagnosticsTestGenerated extends AbstractFirLightTreeDi
public void testReassignOfNonMemberProperty_lateInitialization() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/cfa/reassignOfNonMemberProperty_lateInitialization.kt");
}
@Test
@TestMetadata("smartcastOnThisDuringClassInitialization.kt")
public void testSmartcastOnThisDuringClassInitialization() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/cfa/smartcastOnThisDuringClassInitialization.kt");
}
}
@Nested
@@ -1212,6 +1212,12 @@ public class FirPsiDiagnosticTestGenerated extends AbstractFirPsiDiagnosticTest
public void testReassignOfNonMemberProperty_lateInitialization() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/cfa/reassignOfNonMemberProperty_lateInitialization.kt");
}
@Test
@TestMetadata("smartcastOnThisDuringClassInitialization.kt")
public void testSmartcastOnThisDuringClassInitialization() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/cfa/smartcastOnThisDuringClassInitialization.kt");
}
}
@Nested
@@ -18,10 +18,7 @@ import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.hasBackingField
import org.jetbrains.kotlin.fir.declarations.utils.hasExplicitBackingField
import org.jetbrains.kotlin.fir.declarations.utils.isLateInit
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
import org.jetbrains.kotlin.fir.expressions.calleeReference
import org.jetbrains.kotlin.fir.expressions.unwrapLValue
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.isCatchParameter
import org.jetbrains.kotlin.fir.references.toResolvedPropertySymbol
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
@@ -95,7 +92,7 @@ private fun PropertyInitializationInfoData.checkPropertyAccesses(
scopes: MutableMap<FirPropertySymbol, FirDeclaration?>
) {
fun FirQualifiedAccessExpression.hasCorrectReceiver() =
(dispatchReceiver as? FirThisReceiverExpression)?.calleeReference?.boundSymbol == receiver
(dispatchReceiver.unwrapSmartcastExpression() as? FirThisReceiverExpression)?.calleeReference?.boundSymbol == receiver
for (node in graph.nodes) {
when {
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
import org.jetbrains.kotlin.fir.expressions.calleeReference
import org.jetbrains.kotlin.fir.expressions.dispatchReceiver
import org.jetbrains.kotlin.fir.expressions.unwrapSmartcastExpression
import org.jetbrains.kotlin.fir.references.toResolvedPropertySymbol
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
@@ -51,7 +52,7 @@ class PropertyInitializationInfoCollector(
data: PathAwarePropertyInitializationInfo
): PathAwarePropertyInitializationInfo {
val dataForNode = visitNode(node, data)
val receiver = (node.fir.dispatchReceiver as? FirThisReceiverExpression)?.calleeReference?.boundSymbol
val receiver = (node.fir.dispatchReceiver.unwrapSmartcastExpression() as? FirThisReceiverExpression)?.calleeReference?.boundSymbol
if (receiver != expectedReceiver) return dataForNode
val symbol = node.fir.calleeReference?.toResolvedPropertySymbol() ?: return dataForNode
if (symbol !in localProperties) return dataForNode
@@ -139,7 +139,10 @@ object FirReassignmentAndInvisibleSetterChecker : FirVariableAssignmentChecker()
// Assignments of uninitialized `val`s must be checked via CFG, since the first one is OK.
// See `FirPropertyInitializationAnalyzer` for locals and `FirMemberPropertiesChecker` for backing fields in initializers.
if (property.isLocal && property.requiresInitialization(isForClassInitialization = false)) return
if (isInOwnersInitializer(expression.dispatchReceiver, context) && property.requiresInitialization(isForClassInitialization = true)) return
if (
isInOwnersInitializer(expression.dispatchReceiver.unwrapSmartcastExpression(), context)
&& property.requiresInitialization(isForClassInitialization = true)
) return
reporter.reportOn(expression.lValue.source, FirErrors.VAL_REASSIGNMENT, property, context)
}