From f77a414e93d179604327cb90d857638735e150ae Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Mon, 9 Sep 2019 10:44:47 +0300 Subject: [PATCH] [FIR] Fix passing flow throw try expression --- .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 4 +- .../dfa/cfg/ControlFlowGraphBuilder.kt | 17 +- .../resolve/testData/resolve/cfg/complex.dot | 162 ++++++++++++++++++ .../resolve/testData/resolve/cfg/complex.kt | 32 ++-- .../resolve/testData/resolve/cfg/complex.txt | 23 +++ 5 files changed, 212 insertions(+), 26 deletions(-) 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 283bffb42c5..ccde69f7796 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 @@ -396,7 +396,9 @@ class FirDataFlowAnalyzer(transformer: FirBodyResolveTransformer) : BodyResolveC // ----------------------------------- Try-catch-finally ----------------------------------- fun enterTryExpression(tryExpression: FirTryExpression) { - graphBuilder.enterTryExpression(tryExpression).mergeIncomingFlow() + val (tryExpressionEnterNode, tryMainBlockEnterNode) = graphBuilder.enterTryExpression(tryExpression) + tryExpressionEnterNode.mergeIncomingFlow() + tryMainBlockEnterNode.mergeIncomingFlow() } fun exitTryMainBlock(tryExpression: FirTryExpression) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt index 1c9f59c89d1..6d365e45921 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt @@ -387,30 +387,31 @@ class ControlFlowGraphBuilder { private val finallyEnterNodes: Stack = stackOf() - fun enterTryExpression(tryExpression: FirTryExpression): TryMainBlockEnterNode { + fun enterTryExpression(tryExpression: FirTryExpression): Pair { catchNodeStorages.push(NodeStorage()) - addNewSimpleNode(createTryExpressionEnterNode(tryExpression)) + val enterTryExpressionNode = createTryExpressionEnterNode(tryExpression) + addNewSimpleNode(enterTryExpressionNode) tryExitNodes.push(createTryExpressionExitNode(tryExpression)) levelCounter++ - val tryNode = createTryMainBlockEnterNode(tryExpression) - addNewSimpleNode(tryNode) - addEdge(tryNode, exitNodes.top()) + val enterTryNodeBlock = createTryMainBlockEnterNode(tryExpression) + addNewSimpleNode(enterTryNodeBlock) + addEdge(enterTryNodeBlock, exitNodes.top()) for (catch in tryExpression.catches) { val catchNode = createCatchClauseEnterNode(catch) catchNodeStorage.push(catchNode) - addEdge(tryNode, catchNode) + addEdge(enterTryNodeBlock, catchNode) addEdge(catchNode, exitNodes.top()) } levelCounter++ if (tryExpression.finallyBlock != null) { val finallyEnterNode = createFinallyBlockEnterNode(tryExpression) - addEdge(tryNode, finallyEnterNode) + addEdge(enterTryNodeBlock, finallyEnterNode) finallyEnterNodes.push(finallyEnterNode) } - return tryNode + return enterTryExpressionNode to enterTryNodeBlock } fun exitTryMainBlock(tryExpression: FirTryExpression): TryMainBlockExitNode { diff --git a/compiler/fir/resolve/testData/resolve/cfg/complex.dot b/compiler/fir/resolve/testData/resolve/cfg/complex.dot index a5f647cf0ba..da1d88c1136 100644 --- a/compiler/fir/resolve/testData/resolve/cfg/complex.dot +++ b/compiler/fir/resolve/testData/resolve/cfg/complex.dot @@ -123,4 +123,166 @@ digraph complex_kt { 39 -> {40}; 40 -> {41}; + subgraph cluster_10 { + color=red + 42 [label="Enter function close" style="filled" fillcolor=red]; + 43 [label="Exit function close" style="filled" fillcolor=red]; + } + + 42 -> {43}; + + subgraph cluster_11 { + color=red + 44 [label="Enter function closeFinally" style="filled" fillcolor=red]; + subgraph cluster_12 { + color=blue + 45 [label="Enter block"]; + subgraph cluster_13 { + color=blue + 46 [label="Enter when"]; + subgraph cluster_14 { + color=blue + 47 [label="Enter when branch condition "]; + 48 [label="Access variable this@R|/closeFinally|"]; + 49 [label="Const: Null(null)"]; + 50 [label="Operator =="]; + 51 [label="Exit when branch condition"]; + } + subgraph cluster_15 { + color=blue + 52 [label="Enter when branch condition "]; + 53 [label="Access variable R|/cause|"]; + 54 [label="Const: Null(null)"]; + 55 [label="Operator =="]; + 56 [label="Exit when branch condition"]; + } + subgraph cluster_16 { + color=blue + 57 [label="Enter when branch condition else"]; + 58 [label="Exit when branch condition"]; + } + 59 [label="Enter when branch result"]; + subgraph cluster_17 { + color=blue + 60 [label="Enter block"]; + subgraph cluster_18 { + color=blue + 61 [label="Try expression enter"]; + subgraph cluster_19 { + color=blue + 62 [label="Try main block enter"]; + subgraph cluster_20 { + color=blue + 63 [label="Enter block"]; + 64 [label="Function call: this@R|/AutoCloseable|.R|/AutoCloseable.close|()"]; + 65 [label="Exit block"]; + } + 66 [label="Try main block exit"]; + } + subgraph cluster_21 { + color=blue + 67 [label="Catch enter"]; + subgraph cluster_22 { + color=blue + 68 [label="Enter block"]; + 69 [label="Access variable R|/cause|"]; + 70 [label="Access variable R|/closeException|"]; + 71 [label="Function call: R|/cause|.R|kotlin/addSuppressed|(R|/closeException|)"]; + 72 [label="Exit block"]; + } + 73 [label="Catch exit"]; + } + 74 [label="Try expression exit"]; + } + 75 [label="Exit block"]; + } + 76 [label="Exit when branch result"]; + 77 [label="Enter when branch result"]; + subgraph cluster_23 { + color=blue + 78 [label="Enter block"]; + 79 [label="Function call: this@R|/AutoCloseable|.R|/AutoCloseable.close|()"]; + 80 [label="Exit block"]; + } + 81 [label="Exit when branch result"]; + 82 [label="Enter when branch result"]; + subgraph cluster_24 { + color=blue + 83 [label="Enter block"]; + 84 [label="Exit block"]; + } + 85 [label="Exit when branch result"]; + 86 [label="Exit when"]; + } + 87 [label="Jump: ^closeFinally when () { + ==(this@R|/closeFinally|, Null(null)) -> { + } + ==(R|/cause|, Null(null)) -> { + this@R|/AutoCloseable|.R|/AutoCloseable.close|() + } + else -> { + try { + this@R|/AutoCloseable|.R|/AutoCloseable.close|() + } + catch (closeException: R|kotlin/Throwable|) { + R|/cause|.R|kotlin/addSuppressed|(R|/closeException|) + } + + } +} +"]; + 88 [label="Stub" style="filled" fillcolor=gray]; + 89 [label="Exit block" style="filled" fillcolor=gray]; + } + 90 [label="Exit function closeFinally" style="filled" fillcolor=red]; + } + + 44 -> {45}; + 45 -> {46}; + 46 -> {47}; + 47 -> {48}; + 48 -> {49}; + 49 -> {50}; + 50 -> {51}; + 51 -> {82 52}; + 52 -> {53}; + 53 -> {54}; + 54 -> {55}; + 55 -> {56}; + 56 -> {77 57}; + 57 -> {58}; + 58 -> {59}; + 59 -> {60}; + 60 -> {61}; + 61 -> {62}; + 62 -> {90 67 63}; + 63 -> {64}; + 64 -> {65}; + 65 -> {66}; + 66 -> {74}; + 67 -> {90 68}; + 68 -> {69}; + 69 -> {70}; + 70 -> {71}; + 71 -> {72}; + 72 -> {73}; + 73 -> {74}; + 74 -> {75}; + 75 -> {76}; + 76 -> {86}; + 77 -> {78}; + 78 -> {79}; + 79 -> {80}; + 80 -> {81}; + 81 -> {86}; + 82 -> {83}; + 83 -> {84}; + 84 -> {85}; + 85 -> {86}; + 86 -> {87}; + 87 -> {90}; + 87 -> {88} [style=dotted]; + 88 -> {89} [style=dotted]; + 89 -> {90} [style=dotted]; + } diff --git a/compiler/fir/resolve/testData/resolve/cfg/complex.kt b/compiler/fir/resolve/testData/resolve/cfg/complex.kt index be4242e5d7a..4c152ded023 100644 --- a/compiler/fir/resolve/testData/resolve/cfg/complex.kt +++ b/compiler/fir/resolve/testData/resolve/cfg/complex.kt @@ -11,21 +11,19 @@ fun fetchPluginReleaseDate(pluginId: PluginId, version: String, channel: String? } catch (syntaxException: JsonSyntaxException) { throw ResponseParseException("Can't parse json response", syntaxException) } +} -// val selectedPluginDTO = pluginDTOs -// .firstOrNull { -// it.listed && it.approve && (it.channel == channel || (it.channel == "" && channel == null)) -// } -// ?: return null -// -// val dateString = selectedPluginDTO.cdate ?: throw ResponseParseException("Empty cdate") -// -// return try { -// val dateLong = dateString.toLong() -// Instant.ofEpochMilli(dateLong).atZone(ZoneOffset.UTC).toLocalDate() -// } catch (e: NumberFormatException) { -// throw ResponseParseException("Can't parse long date", e) -// } catch (e: DateTimeException) { -// throw ResponseParseException("Can't convert to date", e) -// } -} \ No newline at end of file +interface AutoCloseable { + fun close() +} + +internal fun AutoCloseable?.closeFinally(cause: Throwable?) = when { + this == null -> {} + cause == null -> close() + else -> + try { + close() + } catch (closeException: Throwable) { + cause.addSuppressed(closeException) + } +} diff --git a/compiler/fir/resolve/testData/resolve/cfg/complex.txt b/compiler/fir/resolve/testData/resolve/cfg/complex.txt index b5decbdba6d..18e112f73f0 100644 --- a/compiler/fir/resolve/testData/resolve/cfg/complex.txt +++ b/compiler/fir/resolve/testData/resolve/cfg/complex.txt @@ -15,3 +15,26 @@ FILE: complex.kt } } + public abstract interface AutoCloseable : R|kotlin/Any| { + public abstract fun close(): R|kotlin/Unit| + + } + internal final fun R|AutoCloseable?|.closeFinally(cause: R|kotlin/Throwable?|): R|kotlin/Unit| { + ^closeFinally when () { + ==(this@R|/closeFinally|, Null(null)) -> { + } + ==(R|/cause|, Null(null)) -> { + this@R|/AutoCloseable|.R|/AutoCloseable.close|() + } + else -> { + try { + this@R|/AutoCloseable|.R|/AutoCloseable.close|() + } + catch (closeException: R|kotlin/Throwable|) { + R|/cause|.R|kotlin/addSuppressed|(R|/closeException|) + } + + } + } + + }