diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/kt39000.kt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/kt39000.kt new file mode 100644 index 00000000000..f2a6e828f2f --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/kt39000.kt @@ -0,0 +1,12 @@ +interface A +class B: A + +val X = B() + +fun foo(b: B) {} + +fun main(a: A) { + if (a === X) { + foo(a) + } +} \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/kt39000.txt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/kt39000.txt new file mode 100644 index 00000000000..4438076e7c2 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/kt39000.txt @@ -0,0 +1,21 @@ +FILE: kt39000.kt + public abstract interface A : R|kotlin/Any| { + } + public final class B : R|A| { + public constructor(): R|B| { + super() + } + + } + public final val X: R|B| = R|/B.B|() + public get(): R|B| + public final fun foo(b: R|B|): R|kotlin/Unit| { + } + public final fun main(a: R|A|): R|kotlin/Unit| { + when () { + ===(R|/a|, R|/X|) -> { + R|/foo|(R|/a|) + } + } + + } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index df12354b1c9..e80f1edff85 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -1989,6 +1989,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/kt37327.kt"); } + @TestMetadata("kt39000.kt") + public void testKt39000() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/kt39000.kt"); + } + @TestMetadata("multipleCasts.kt") public void testMultipleCasts() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/multipleCasts.kt"); diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java index 25bc3496228..4a065812064 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -1989,6 +1989,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/kt37327.kt"); } + @TestMetadata("kt39000.kt") + public void testKt39000() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/kt39000.kt"); + } + @TestMetadata("multipleCasts.kt") public void testMultipleCasts() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/multipleCasts.kt"); 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 6a6e72bebb5..3092cabb3fb 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 @@ -411,6 +411,10 @@ abstract class FirDataFlowAnalyzer( leftIsNullable -> processEqNull(node, leftOperand, operation.invert()) rightIsNullable -> processEqNull(node, rightOperand, operation.invert()) } + + if (operation == FirOperation.IDENTITY || operation == FirOperation.NOT_IDENTITY) { + processIdentity(node, leftOperand, rightOperand, operation) + } } private fun processEqNull(node: OperatorCallNode, operand: FirExpression, operation: FirOperation) { @@ -444,6 +448,28 @@ abstract class FirDataFlowAnalyzer( node.flow = flow } + private fun processIdentity(node: OperatorCallNode, leftOperand: FirExpression, rightOperand: FirExpression, operation: FirOperation) { + val flow = node.flow + val expressionVariable = variableStorage.getOrCreateVariable(node.previousFlow, node.fir) + val leftOperandVariable = variableStorage.getOrCreateVariable(node.previousFlow, leftOperand) + val rightOperandVariable = variableStorage.getOrCreateVariable(node.previousFlow, rightOperand) + val leftOperandType = leftOperand.coneType + val rightOperandType = rightOperand.coneType + val isEq = operation.isEq() + + if (leftOperandVariable.isReal()) { + flow.addImplication((expressionVariable eq isEq) implies (leftOperandVariable typeEq rightOperandType)) + flow.addImplication((expressionVariable notEq isEq) implies (leftOperandVariable typeNotEq rightOperandType)) + } + + if (rightOperandVariable.isReal()) { + flow.addImplication((expressionVariable eq isEq) implies (rightOperandVariable typeEq leftOperandType)) + flow.addImplication((expressionVariable notEq isEq) implies (rightOperandVariable typeNotEq leftOperandType)) + } + + node.flow = flow + } + // ----------------------------------- Jump ----------------------------------- fun exitJump(jump: FirJump<*>) { diff --git a/compiler/testData/diagnostics/tests/smartCasts/fakeSmartCastOnEquality.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/fakeSmartCastOnEquality.fir.kt index 63e29c46afd..278a5576dbc 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/fakeSmartCastOnEquality.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/fakeSmartCastOnEquality.fir.kt @@ -15,11 +15,11 @@ fun check(x1: Derived1, x: Base) { } if (x1 === x) { // OK - x.foo() + x.foo() } if (x1 !== x) {} else { // OK - x.foo() + x.foo() } } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/39.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/39.fir.kt index e8b2896a7df..63b8f6abfe2 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/39.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/39.fir.kt @@ -21,8 +21,8 @@ fun case_2(x: Number) { val y: Int? = null if (x === y) { - x - x.inv() + x + x.inv() } } @@ -31,8 +31,8 @@ fun case_3(x: Number) { var y: Int? = null if (x === y) { - x - x.inv() + x + x.inv() } } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/48.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/48.fir.kt index 75bef048946..e94a1a98baf 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/48.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/48.fir.kt @@ -25,8 +25,8 @@ fun case_2(x: Any?, y: Any?) { if (x as Int === y) { x x.inv(10) - y - y.inv(10) + y + y.inv(10) } } @@ -53,7 +53,7 @@ fun case_4(x: Any?, y: Any?) { if (y === x as Int) { x x.inv(10) - y - y.inv(10) + y + y.inv(10) } }