From 4a381d4b83699eaca13268f46152926921d4f966 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 5 Feb 2021 12:34:20 +0300 Subject: [PATCH] FIR DFA: update receivers properly in case of single flow in merge point --- .../FirBlackBoxCodegenTestGenerated.java | 6 +++ .../PersistentImplicitReceiverStack.kt | 2 +- .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 27 +++++++++---- .../fir/resolve/dfa/PersistentLogicSystem.kt | 3 -- .../testData/codegen/box/fir/LookupTags.kt | 39 +++++++++++++++++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 +++ .../IrBlackBoxCodegenTestGenerated.java | 6 +++ .../LightAnalysisModeTestGenerated.java | 5 +++ 8 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 compiler/testData/codegen/box/fir/LookupTags.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index b878b930906..7f21b3dbeda 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -14852,6 +14852,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/fir/IrBuiltIns.kt"); } + @Test + @TestMetadata("LookupTags.kt") + public void testLookupTags() throws Exception { + runTest("compiler/testData/codegen/box/fir/LookupTags.kt"); + } + @Test @TestMetadata("NameHighlighter.kt") public void testNameHighlighter() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/PersistentImplicitReceiverStack.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/PersistentImplicitReceiverStack.kt index b449cc0a153..d7be8b91e7d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/PersistentImplicitReceiverStack.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/PersistentImplicitReceiverStack.kt @@ -37,7 +37,7 @@ class PersistentImplicitReceiverStack private constructor( fun add(name: Name?, value: ImplicitReceiverValue<*>): PersistentImplicitReceiverStack { val stack = stack.add(value) - val originalTypes = originalTypes.add(value.type) + val originalTypes = originalTypes.add(value.originalType) val index = stack.size - 1 val indexesPerLabel = name?.let { indexesPerLabel.put(it, index) } ?: indexesPerLabel val indexesPerSymbol = indexesPerSymbol.put(value.boundSymbol, index) 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 6d3b14621f3..e9e965b1d18 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 @@ -582,7 +582,7 @@ abstract class FirDataFlowAnalyzer( syntheticElseNode.mergeIncomingFlow() } } - whenExitNode.mergeIncomingFlow(updateReceivers = true) + whenExitNode.mergeIncomingFlow() } // ----------------------------------- While Loop ----------------------------------- @@ -675,7 +675,7 @@ abstract class FirDataFlowAnalyzer( fun enterFinallyBlock() { // NB: fork to isolate effects inside the finally block // Otherwise, changes in the finally block could affect the previous nodes: try main block and catch clauses. - graphBuilder.enterFinallyBlock().mergeIncomingFlow(shouldForkFlow = true) + graphBuilder.enterFinallyBlock().mergeIncomingFlow(updateReceivers = true, shouldForkFlow = true) } fun exitFinallyBlock(tryExpression: FirTryExpression) { @@ -1144,15 +1144,28 @@ abstract class FirDataFlowAnalyzer( private val CFGNode<*>.origin: CFGNode<*> get() = if (this is StubNode) firstPreviousNode else this private fun > T.mergeIncomingFlow( + // This flag should be set true if we're changing flow branches from one to another (e.g. in when, try->catch) updateReceivers: Boolean = false, shouldForkFlow: Boolean = false ): T = this.also { node -> - val previousFlows = if (node.isDead) - node.previousNodes.mapNotNull { runIf(!node.incomingEdges.getValue(it).kind.isBack) { it.flow } } - else - node.previousNodes.mapNotNull { prev -> prev.takeIf { node.incomingEdges.getValue(it).kind.usedInDfa }?.flow } + val previousFlows = mutableListOf() + var deadForwardCount = 0 + for (previousNode in previousNodes) { + val incomingEdgeKind = node.incomingEdges.getValue(previousNode).kind + if (node.isDead) { + if (!incomingEdgeKind.isBack) { + previousFlows += previousNode.flow + } + } else if (incomingEdgeKind.usedInDfa) { + previousFlows += previousNode.flow + } + if (incomingEdgeKind == EdgeKind.DeadForward) { + deadForwardCount++ + } + } var flow = logicSystem.joinFlow(previousFlows) - if (updateReceivers) { + // deadForwardCount should be added due to cases like merge after 'if (...) return else ...' + if (updateReceivers || previousFlows.size + deadForwardCount > 1) { logicSystem.updateAllReceivers(flow) } if (shouldForkFlow) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PersistentLogicSystem.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PersistentLogicSystem.kt index 567f9226ffa..61aaa618a76 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PersistentLogicSystem.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PersistentLogicSystem.kt @@ -138,9 +138,6 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste } commonFlow.addVariableAliases(aliasedVariablesThatDontChangeAlias) - - updateAllReceivers(commonFlow) - return commonFlow } diff --git a/compiler/testData/codegen/box/fir/LookupTags.kt b/compiler/testData/codegen/box/fir/LookupTags.kt new file mode 100644 index 00000000000..4a22d1e8754 --- /dev/null +++ b/compiler/testData/codegen/box/fir/LookupTags.kt @@ -0,0 +1,39 @@ +// TARGET_BACKEND: JVM + +abstract class ConeClassLikeLookupTag { + abstract val status: String +} + +class ConeClassLikeLookupTagImpl : ConeClassLikeLookupTag() { + override var status: String = "" + private set + + fun change(newStatus: String) { + status = newStatus + } +} + +class ConeClassLikeErrorLookupTag : ConeClassLikeLookupTag() { + override val status: String + get() = "ERROR" +} + +fun ConeClassLikeLookupTag.foo(): String { + (this as? ConeClassLikeLookupTagImpl)?.status?.takeIf { it == "OK" }?.let { return it } + return status.also { + (this as? ConeClassLikeLookupTagImpl)?.bar(it) + } +} + +fun ConeClassLikeLookupTagImpl.bar(s: String) { + change(s) +} + +fun box(): String { + val tag = ConeClassLikeErrorLookupTag() + tag.foo() + val tag2 = ConeClassLikeLookupTagImpl() + tag2.change("OK") + tag2.foo() + return tag2.status +} \ No newline at end of file diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 78043e67679..4fabe55fdda 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -14852,6 +14852,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/fir/IrBuiltIns.kt"); } + @Test + @TestMetadata("LookupTags.kt") + public void testLookupTags() throws Exception { + runTest("compiler/testData/codegen/box/fir/LookupTags.kt"); + } + @Test @TestMetadata("NameHighlighter.kt") public void testNameHighlighter() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 6ec08af0bff..32b9bcdcee2 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -14852,6 +14852,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/fir/IrBuiltIns.kt"); } + @Test + @TestMetadata("LookupTags.kt") + public void testLookupTags() throws Exception { + runTest("compiler/testData/codegen/box/fir/LookupTags.kt"); + } + @Test @TestMetadata("NameHighlighter.kt") public void testNameHighlighter() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index c3af176732e..f89ad546ddd 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -12283,6 +12283,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/fir/IrBuiltIns.kt"); } + @TestMetadata("LookupTags.kt") + public void testLookupTags() throws Exception { + runTest("compiler/testData/codegen/box/fir/LookupTags.kt"); + } + @TestMetadata("NameHighlighter.kt") public void testNameHighlighter() throws Exception { runTest("compiler/testData/codegen/box/fir/NameHighlighter.kt");