[FIR] Add inlining of control flow graphs of in-place anonymous functions
This commit is contained in:
+1
-1
@@ -24,7 +24,7 @@ class DummyFirDataFlowAnalyzer : FirDataFlowAnalyzer() {
|
||||
|
||||
override fun enterFunction(function: FirFunction<*>) {}
|
||||
|
||||
override fun exitFunction(function: FirFunction<*>): ControlFlowGraph = ControlFlowGraph(DUMMY)
|
||||
override fun exitFunction(function: FirFunction<*>): ControlFlowGraph? = null
|
||||
|
||||
override fun enterBlock(block: FirBlock) {}
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ abstract class FirDataFlowAnalyzer {
|
||||
// ----------------------------------- Named function -----------------------------------
|
||||
|
||||
abstract fun enterFunction(function: FirFunction<*>)
|
||||
abstract fun exitFunction(function: FirFunction<*>): ControlFlowGraph
|
||||
abstract fun exitFunction(function: FirFunction<*>): ControlFlowGraph?
|
||||
|
||||
// ----------------------------------- Property -----------------------------------
|
||||
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ class FirDataFlowAnalyzerImpl(transformer: FirBodyResolveTransformer) : FirDataF
|
||||
}
|
||||
}
|
||||
|
||||
override fun exitFunction(function: FirFunction<*>): ControlFlowGraph {
|
||||
override fun exitFunction(function: FirFunction<*>): ControlFlowGraph? {
|
||||
val (node, graph) = graphBuilder.exitFunction(function)
|
||||
node.passFlow()
|
||||
for (valueParameter in function.valueParameters) {
|
||||
|
||||
+51
-8
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.dfa.cfg
|
||||
|
||||
import org.jetbrains.kotlin.contracts.description.InvocationKind
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirAbstractPropertyAccessor
|
||||
@@ -65,18 +66,48 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() {
|
||||
is FirConstructor -> function.name.asString()
|
||||
else -> throw IllegalArgumentException("Unknown function: ${function.render()}")
|
||||
}
|
||||
graphs.push(ControlFlowGraph(name))
|
||||
functionExitNodes.push(createFunctionExitNode(function))
|
||||
lexicalScopes.push(stackOf())
|
||||
return createFunctionEnterNode(function).also { lastNodes.push(it) }.also { levelCounter++ }
|
||||
val invocationKind = function.invocationKind
|
||||
val isInplace = invocationKind.isInplace()
|
||||
if (!isInplace) {
|
||||
graphs.push(ControlFlowGraph(name))
|
||||
}
|
||||
val enterNode = createFunctionEnterNode(function, isInplace).also {
|
||||
if (isInplace) {
|
||||
addNewSimpleNode(it)
|
||||
} else {
|
||||
lexicalScopes.push(stackOf())
|
||||
lastNodes.push(it)
|
||||
}
|
||||
}
|
||||
val exitNode = createFunctionExitNode(function, isInplace)
|
||||
|
||||
@Suppress("NON_EXHAUSTIVE_WHEN")
|
||||
when (invocationKind) {
|
||||
InvocationKind.AT_LEAST_ONCE -> addEdge(exitNode, enterNode)
|
||||
InvocationKind.AT_MOST_ONCE -> addEdge(enterNode, exitNode)
|
||||
}
|
||||
|
||||
functionExitNodes.push(exitNode)
|
||||
levelCounter++
|
||||
return enterNode
|
||||
}
|
||||
|
||||
fun exitFunction(function: FirFunction<*>): Pair<FunctionExitNode, ControlFlowGraph> {
|
||||
fun exitFunction(function: FirFunction<*>): Pair<FunctionExitNode, ControlFlowGraph?> {
|
||||
levelCounter--
|
||||
val exitNode = functionExitNodes.pop()
|
||||
addEdge(lastNodes.pop(), exitNode)
|
||||
lexicalScopes.pop()
|
||||
return exitNode to graphs.pop()
|
||||
val isInplace = function.isInplace()
|
||||
if (isInplace) {
|
||||
addNewSimpleNode(exitNode)
|
||||
} else {
|
||||
addEdge(lastNodes.pop(), exitNode)
|
||||
lexicalScopes.pop()
|
||||
}
|
||||
val graph = if (!isInplace) {
|
||||
graphs.pop()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return exitNode to graph
|
||||
}
|
||||
|
||||
// ----------------------------------- Block -----------------------------------
|
||||
@@ -503,4 +534,16 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() {
|
||||
from.followingNodes += to
|
||||
to.previousNodes += from
|
||||
}
|
||||
|
||||
private val FirFunction<*>.invocationKind: InvocationKind?
|
||||
get() = (this as? FirAnonymousFunction)?.invocationKind
|
||||
|
||||
private fun InvocationKind?.isInplace(): Boolean {
|
||||
return this != null && this != InvocationKind.UNKNOWN
|
||||
}
|
||||
|
||||
private fun FirFunction<*>.isInplace(): Boolean {
|
||||
val invocationKind = this.invocationKind
|
||||
return invocationKind != null && invocationKind != InvocationKind.UNKNOWN
|
||||
}
|
||||
}
|
||||
+9
-4
@@ -54,13 +54,18 @@ abstract class ControlFlowGraphNodeBuilder {
|
||||
|
||||
protected fun createPropertyEnterNode(fir: FirProperty): PropertyEnterNode = PropertyEnterNode(graph, fir, levelCounter)
|
||||
|
||||
protected fun createFunctionEnterNode(fir: FirFunction<*>): FunctionEnterNode =
|
||||
protected fun createFunctionEnterNode(fir: FirFunction<*>, isInPlace: Boolean): FunctionEnterNode =
|
||||
FunctionEnterNode(graph, fir, levelCounter).also {
|
||||
graph.enterNode = it
|
||||
if (!isInPlace) {
|
||||
graph.enterNode = it
|
||||
}
|
||||
}
|
||||
|
||||
protected fun createFunctionExitNode(fir: FirFunction<*>): FunctionExitNode = FunctionExitNode(graph, fir, levelCounter).also {
|
||||
graph.exitNode = it
|
||||
protected fun createFunctionExitNode(fir: FirFunction<*>, isInPlace: Boolean): FunctionExitNode =
|
||||
FunctionExitNode(graph, fir, levelCounter).also {
|
||||
if (!isInPlace) {
|
||||
graph.exitNode = it
|
||||
}
|
||||
}
|
||||
|
||||
protected fun createBinaryOrEnterNode(fir: FirBinaryLogicExpression): BinaryOrEnterNode =
|
||||
|
||||
+3
-2
@@ -603,8 +603,9 @@ open class FirBodyResolveTransformer(
|
||||
dataFlowAnalyzer.enterFunction(function)
|
||||
super.transformFunction(function, data).also {
|
||||
val result = it.single as FirFunction<*>
|
||||
val controlFlowGraph = dataFlowAnalyzer.exitFunction(result)
|
||||
result.transformControlFlowGraphReference(ControlFlowGraphReferenceTransformer, controlFlowGraph)
|
||||
dataFlowAnalyzer.exitFunction(result)?.let { controlFlowGraph ->
|
||||
result.transformControlFlowGraphReference(ControlFlowGraphReferenceTransformer, controlFlowGraph)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ FILE: complex.kt
|
||||
@R|kotlin/jvm/Throws|(<getClass>(<Unresolved name: IOException>#), <getClass>(<Unresolved name: ResponseParseException>#)) public final fun fetchPluginReleaseDate(pluginId: R|class error: Symbol not found, for `PluginId`|, version: R|kotlin/String|, channel: R|kotlin/String?|): R|class error: Symbol not found, for `LocalDate?`| {
|
||||
lval url: R|kotlin/String| = <strcat>(String(https://plugins.jetbrains.com/api/plugins/), R|<local>/pluginId|.<Unresolved name: idString>#, String(/updates?version=), R|<local>/version|)
|
||||
lval pluginDTOs: R|kotlin/Array<class error: Symbol not found, for `PluginDTO`>| = try {
|
||||
<Unresolved name: HttpRequests>#.<Unresolved name: request>#(R|<local>/url|).<Unresolved name: connect>#(<L> = connect@fun <implicit>.<anonymous>(): <implicit> {
|
||||
<Unresolved name: HttpRequests>#.<Unresolved name: request>#(R|<local>/url|).<Unresolved name: connect>#(<L> = connect@fun <implicit>.<anonymous>(): <implicit> <kind=EXACTLY_ONCE> {
|
||||
GsonBuilder#().create#().fromJson#(it#.inputStream#.reader#(), <getClass>(Array#<R|class error: Symbol not found, for `PluginDTO`|>()).java#)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
digraph lambdas_kt {
|
||||
subgraph run {
|
||||
0 [shape=box label="Enter function run"];
|
||||
1 [shape=box label="Enter block"];
|
||||
2 [shape=box label="Function call: R|<local>/block|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/Unit|>|()"];
|
||||
3 [shape=box label="Exit block"];
|
||||
4 [shape=box label="Exit function run"];
|
||||
|
||||
0 -> {1};
|
||||
1 -> {2};
|
||||
2 -> {3};
|
||||
3 -> {4};
|
||||
}
|
||||
|
||||
subgraph test_1 {
|
||||
5 [shape=box label="Enter function test_1"];
|
||||
6 [shape=box label="Enter block"];
|
||||
7 [shape=box label="Enter when"];
|
||||
8 [shape=box label="Enter when branch condition "];
|
||||
9 [shape=box label="Access variable R|<local>/x|"];
|
||||
10 [shape=box label="Type operator: x is Int"];
|
||||
11 [shape=box label="Exit when branch condition"];
|
||||
12 [shape=box label="Enter block"];
|
||||
13 [shape=box label="Enter function anonymousFunction"];
|
||||
14 [shape=box label="Enter block"];
|
||||
15 [shape=box label="Access variable R|<local>/x|"];
|
||||
16 [shape=box label="Function call: R|<local>/x|.R|kotlin/Int.inc|()"];
|
||||
17 [shape=box label="Exit block"];
|
||||
18 [shape=box label="Exit function anonymousFunction"];
|
||||
19 [shape=box label="Function call: R|/run|(<L> = run@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
|
||||
R|<local>/x|.R|kotlin/Int.inc|()
|
||||
}
|
||||
)"];
|
||||
20 [shape=box label="Exit block"];
|
||||
21 [shape=box label="Exit when branch result"];
|
||||
22 [shape=box label="Enter when branch condition else"];
|
||||
23 [shape=box label="Exit when branch condition"];
|
||||
24 [shape=box label="Enter block"];
|
||||
25 [shape=box label="Exit block"];
|
||||
26 [shape=box label="Exit when branch result"];
|
||||
27 [shape=box label="Exit when"];
|
||||
28 [shape=box label="Exit block"];
|
||||
29 [shape=box label="Exit function test_1"];
|
||||
|
||||
5 -> {6};
|
||||
6 -> {7};
|
||||
7 -> {8};
|
||||
8 -> {9};
|
||||
9 -> {10};
|
||||
10 -> {11};
|
||||
11 -> {12 22};
|
||||
12 -> {13};
|
||||
13 -> {14};
|
||||
14 -> {15};
|
||||
15 -> {16};
|
||||
16 -> {17};
|
||||
17 -> {18};
|
||||
18 -> {19};
|
||||
19 -> {20};
|
||||
20 -> {21};
|
||||
21 -> {27};
|
||||
22 -> {23};
|
||||
23 -> {24};
|
||||
24 -> {25};
|
||||
25 -> {26};
|
||||
26 -> {27};
|
||||
27 -> {28};
|
||||
28 -> {29};
|
||||
}
|
||||
|
||||
subgraph <anonymous> {
|
||||
30 [shape=box label="Enter function anonymousFunction"];
|
||||
31 [shape=box label="Enter block"];
|
||||
32 [shape=box label="Access variable R|<local>/x|"];
|
||||
33 [shape=box label="Function call: R|<local>/x|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()"];
|
||||
34 [shape=box label="Exit block"];
|
||||
35 [shape=box label="Exit function anonymousFunction"];
|
||||
|
||||
30 -> {31};
|
||||
31 -> {32};
|
||||
32 -> {33};
|
||||
33 -> {34};
|
||||
34 -> {35};
|
||||
}
|
||||
|
||||
subgraph test_2 {
|
||||
36 [shape=box label="Enter function test_2"];
|
||||
37 [shape=box label="Enter block"];
|
||||
38 [shape=box label="Enter when"];
|
||||
39 [shape=box label="Enter when branch condition "];
|
||||
40 [shape=box label="Access variable R|<local>/x|"];
|
||||
41 [shape=box label="Type operator: x is Int"];
|
||||
42 [shape=box label="Exit when branch condition"];
|
||||
43 [shape=box label="Enter block"];
|
||||
44 [shape=box label="Variable declaration: lval lambda: R|kotlin/Function0<class error: Ambiguity: inc, [kotlin/inc, kotlin/inc]>|"];
|
||||
45 [shape=box label="Exit block"];
|
||||
46 [shape=box label="Exit when branch result"];
|
||||
47 [shape=box label="Enter when branch condition else"];
|
||||
48 [shape=box label="Exit when branch condition"];
|
||||
49 [shape=box label="Enter block"];
|
||||
50 [shape=box label="Exit block"];
|
||||
51 [shape=box label="Exit when branch result"];
|
||||
52 [shape=box label="Exit when"];
|
||||
53 [shape=box label="Exit block"];
|
||||
54 [shape=box label="Exit function test_2"];
|
||||
|
||||
36 -> {37};
|
||||
37 -> {38};
|
||||
38 -> {39};
|
||||
39 -> {40};
|
||||
40 -> {41};
|
||||
41 -> {42};
|
||||
42 -> {43 47};
|
||||
43 -> {44};
|
||||
44 -> {45};
|
||||
45 -> {46};
|
||||
46 -> {52};
|
||||
47 -> {48};
|
||||
48 -> {49};
|
||||
49 -> {50};
|
||||
50 -> {51};
|
||||
51 -> {52};
|
||||
52 -> {53};
|
||||
53 -> {54};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
fun run(block: () -> Unit) {
|
||||
block()
|
||||
}
|
||||
|
||||
fun test_1(x: Any?) {
|
||||
if (x is Int) {
|
||||
run {
|
||||
x.inc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test_2(x: Any?) {
|
||||
if (x is Int) {
|
||||
val lambda = {
|
||||
x.inc()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
FILE: lambdas.kt
|
||||
public final fun run(block: R|kotlin/Function0<kotlin/Unit>|): R|kotlin/Unit| {
|
||||
R|<local>/block|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/Unit|>|()
|
||||
}
|
||||
public final fun test_1(x: R|kotlin/Any?|): R|kotlin/Unit| {
|
||||
when () {
|
||||
(R|<local>/x| is R|kotlin/Int|) -> {
|
||||
R|/run|(<L> = run@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
|
||||
R|<local>/x|.R|kotlin/Int.inc|()
|
||||
}
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_2(x: R|kotlin/Any?|): R|kotlin/Unit| {
|
||||
when () {
|
||||
(R|<local>/x| is R|kotlin/Int|) -> {
|
||||
lval lambda: R|kotlin/Function0<class error: Ambiguity: inc, [kotlin/inc, kotlin/inc]>| = fun <anonymous>(): <ERROR TYPE REF: Ambiguity: inc, [kotlin/inc, kotlin/inc]> {
|
||||
R|<local>/x|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()
|
||||
}
|
||||
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,7 @@ FILE: propertiesAndInitBlocks.kt
|
||||
public set(value: R|kotlin/Int|): R|kotlin/Unit| {
|
||||
F|/x2| = Int(1)
|
||||
}
|
||||
public final val x3: R|kotlin/Unit| = R|/run|(<L> = run@fun <anonymous>(): R|kotlin/Unit| {
|
||||
public final val x3: R|kotlin/Unit| = R|/run|(<L> = run@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
|
||||
local final fun foo(): R|kotlin/Unit| {
|
||||
lval c: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(1))
|
||||
throw <Ambiguity: Exception, [java/lang/Exception.Exception, java/lang/Exception.Exception]>#()
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
digraph inPlaceLambdas_kt {
|
||||
subgraph foo {
|
||||
0 [shape=box label="Enter function foo"];
|
||||
1 [shape=box label="Exit function foo"];
|
||||
|
||||
0 -> {1};
|
||||
}
|
||||
|
||||
subgraph bar {
|
||||
2 [shape=box label="Enter function bar"];
|
||||
3 [shape=box label="Exit function bar"];
|
||||
|
||||
2 -> {3};
|
||||
}
|
||||
|
||||
subgraph run {
|
||||
4 [shape=box label="Enter function run"];
|
||||
5 [shape=box label="Enter block"];
|
||||
6 [shape=box label="Function call: R|<local>/block|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/Unit|>|()"];
|
||||
7 [shape=box label="Exit block"];
|
||||
8 [shape=box label="Exit function run"];
|
||||
|
||||
4 -> {5};
|
||||
5 -> {6};
|
||||
6 -> {7};
|
||||
7 -> {8};
|
||||
}
|
||||
|
||||
subgraph test_1 {
|
||||
9 [shape=box label="Enter function test_1"];
|
||||
10 [shape=box label="Enter block"];
|
||||
11 [shape=box label="Enter when"];
|
||||
12 [shape=box label="Enter when branch condition "];
|
||||
13 [shape=box label="Access variable R|<local>/x|"];
|
||||
14 [shape=box label="Type operator: x is A"];
|
||||
15 [shape=box label="Exit when branch condition"];
|
||||
16 [shape=box label="Enter block"];
|
||||
17 [shape=box label="Enter function anonymousFunction"];
|
||||
18 [shape=box label="Enter block"];
|
||||
19 [shape=box label="Access variable R|<local>/x|"];
|
||||
20 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
|
||||
21 [shape=box label="Exit block"];
|
||||
22 [shape=box label="Exit function anonymousFunction"];
|
||||
23 [shape=box label="Function call: R|/run|(<L> = run@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
|
||||
R|<local>/x|.R|/A.foo|()
|
||||
}
|
||||
)"];
|
||||
24 [shape=box label="Exit block"];
|
||||
25 [shape=box label="Exit when branch result"];
|
||||
26 [shape=box label="Enter when branch condition else"];
|
||||
27 [shape=box label="Exit when branch condition"];
|
||||
28 [shape=box label="Enter block"];
|
||||
29 [shape=box label="Exit block"];
|
||||
30 [shape=box label="Exit when branch result"];
|
||||
31 [shape=box label="Exit when"];
|
||||
32 [shape=box label="Exit block"];
|
||||
33 [shape=box label="Exit function test_1"];
|
||||
|
||||
9 -> {10};
|
||||
10 -> {11};
|
||||
11 -> {12};
|
||||
12 -> {13};
|
||||
13 -> {14};
|
||||
14 -> {15};
|
||||
15 -> {16 26};
|
||||
16 -> {17};
|
||||
17 -> {18};
|
||||
18 -> {19};
|
||||
19 -> {20};
|
||||
20 -> {21};
|
||||
21 -> {22};
|
||||
22 -> {23};
|
||||
23 -> {24};
|
||||
24 -> {25};
|
||||
25 -> {31};
|
||||
26 -> {27};
|
||||
27 -> {28};
|
||||
28 -> {29};
|
||||
29 -> {30};
|
||||
30 -> {31};
|
||||
31 -> {32};
|
||||
32 -> {33};
|
||||
}
|
||||
|
||||
subgraph test_2 {
|
||||
34 [shape=box label="Enter function test_2"];
|
||||
35 [shape=box label="Enter block"];
|
||||
36 [shape=box label="Enter function anonymousFunction"];
|
||||
37 [shape=box label="Enter block"];
|
||||
38 [shape=box label="Access variable R|<local>/x|"];
|
||||
39 [shape=box label="Type operator: x as B"];
|
||||
40 [shape=box label="Exit block"];
|
||||
41 [shape=box label="Exit function anonymousFunction"];
|
||||
42 [shape=box label="Function call: R|/run|(<L> = run@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
|
||||
(R|<local>/x| as R|B|)
|
||||
}
|
||||
)"];
|
||||
43 [shape=box label="Access variable R|<local>/x|"];
|
||||
44 [shape=box label="Function call: R|<local>/x|.R|/B.bar|()"];
|
||||
45 [shape=box label="Exit block"];
|
||||
46 [shape=box label="Exit function test_2"];
|
||||
|
||||
34 -> {35};
|
||||
35 -> {36};
|
||||
36 -> {37};
|
||||
37 -> {38};
|
||||
38 -> {39};
|
||||
39 -> {40};
|
||||
40 -> {41};
|
||||
41 -> {42};
|
||||
42 -> {43};
|
||||
43 -> {44};
|
||||
44 -> {45};
|
||||
45 -> {46};
|
||||
}
|
||||
|
||||
subgraph test_3 {
|
||||
47 [shape=box label="Enter function test_3"];
|
||||
48 [shape=box label="Enter block"];
|
||||
49 [shape=box label="Enter when"];
|
||||
50 [shape=box label="Enter when branch condition "];
|
||||
51 [shape=box label="Access variable R|<local>/x|"];
|
||||
52 [shape=box label="Type operator: x is A"];
|
||||
53 [shape=box label="Exit when branch condition"];
|
||||
54 [shape=box label="Enter block"];
|
||||
55 [shape=box label="Enter function anonymousFunction"];
|
||||
56 [shape=box label="Enter block"];
|
||||
57 [shape=box label="Access variable R|<local>/x|"];
|
||||
58 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
|
||||
59 [shape=box label="Access variable R|<local>/x|"];
|
||||
60 [shape=box label="Type operator: x as B"];
|
||||
61 [shape=box label="Exit block"];
|
||||
62 [shape=box label="Exit function anonymousFunction"];
|
||||
63 [shape=box label="Function call: R|/run|(<L> = run@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
|
||||
R|<local>/x|.R|/A.foo|()
|
||||
(R|<local>/x| as R|B|)
|
||||
}
|
||||
)"];
|
||||
64 [shape=box label="Access variable R|<local>/x|"];
|
||||
65 [shape=box label="Function call: R|<local>/x|.R|/B.bar|()"];
|
||||
66 [shape=box label="Exit block"];
|
||||
67 [shape=box label="Exit when branch result"];
|
||||
68 [shape=box label="Enter when branch condition else"];
|
||||
69 [shape=box label="Exit when branch condition"];
|
||||
70 [shape=box label="Enter block"];
|
||||
71 [shape=box label="Exit block"];
|
||||
72 [shape=box label="Exit when branch result"];
|
||||
73 [shape=box label="Exit when"];
|
||||
74 [shape=box label="Exit block"];
|
||||
75 [shape=box label="Exit function test_3"];
|
||||
|
||||
47 -> {48};
|
||||
48 -> {49};
|
||||
49 -> {50};
|
||||
50 -> {51};
|
||||
51 -> {52};
|
||||
52 -> {53};
|
||||
53 -> {54 68};
|
||||
54 -> {55};
|
||||
55 -> {56};
|
||||
56 -> {57};
|
||||
57 -> {58};
|
||||
58 -> {59};
|
||||
59 -> {60};
|
||||
60 -> {61};
|
||||
61 -> {62};
|
||||
62 -> {63};
|
||||
63 -> {64};
|
||||
64 -> {65};
|
||||
65 -> {66};
|
||||
66 -> {67};
|
||||
67 -> {73};
|
||||
68 -> {69};
|
||||
69 -> {70};
|
||||
70 -> {71};
|
||||
71 -> {72};
|
||||
72 -> {73};
|
||||
73 -> {74};
|
||||
74 -> {75};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
interface A {
|
||||
fun foo()
|
||||
}
|
||||
|
||||
interface B {
|
||||
fun bar()
|
||||
}
|
||||
|
||||
|
||||
fun run(block: () -> Unit) {
|
||||
block()
|
||||
}
|
||||
|
||||
fun test_1(x: Any?) {
|
||||
if (x is A) {
|
||||
run {
|
||||
x.foo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test_2(x: Any?) {
|
||||
run {
|
||||
x as B
|
||||
}
|
||||
x.bar()
|
||||
}
|
||||
|
||||
fun test_3(x: Any?) {
|
||||
if (x is A) {
|
||||
run {
|
||||
x.foo()
|
||||
x as B
|
||||
}
|
||||
x.bar()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
FILE: inPlaceLambdas.kt
|
||||
public abstract interface A : R|kotlin/Any| {
|
||||
public abstract fun foo(): R|kotlin/Unit|
|
||||
|
||||
}
|
||||
public abstract interface B : R|kotlin/Any| {
|
||||
public abstract fun bar(): R|kotlin/Unit|
|
||||
|
||||
}
|
||||
public final fun run(block: R|kotlin/Function0<kotlin/Unit>|): R|kotlin/Unit| {
|
||||
R|<local>/block|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/Unit|>|()
|
||||
}
|
||||
public final fun test_1(x: R|kotlin/Any?|): R|kotlin/Unit| {
|
||||
when () {
|
||||
(R|<local>/x| is R|A|) -> {
|
||||
R|/run|(<L> = run@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
|
||||
R|<local>/x|.R|/A.foo|()
|
||||
}
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_2(x: R|kotlin/Any?|): R|kotlin/Unit| {
|
||||
R|/run|(<L> = run@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
|
||||
(R|<local>/x| as R|B|)
|
||||
}
|
||||
)
|
||||
R|<local>/x|.R|/B.bar|()
|
||||
}
|
||||
public final fun test_3(x: R|kotlin/Any?|): R|kotlin/Unit| {
|
||||
when () {
|
||||
(R|<local>/x| is R|A|) -> {
|
||||
R|/run|(<L> = run@fun <anonymous>(): R|kotlin/Unit| <kind=EXACTLY_ONCE> {
|
||||
R|<local>/x|.R|/A.foo|()
|
||||
(R|<local>/x| as R|B|)
|
||||
}
|
||||
)
|
||||
R|<local>/x|.R|/B.bar|()
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+10
@@ -51,6 +51,11 @@ public class FirCfgBuildingTestGenerated extends AbstractFirCfgBuildingTest {
|
||||
runTest("compiler/fir/resolve/testData/resolve/cfg/jumps.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("lambdas.kt")
|
||||
public void testLambdas() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/cfg/lambdas.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("loops.kt")
|
||||
public void testLoops() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/cfg/loops.kt");
|
||||
@@ -109,6 +114,11 @@ public class FirCfgBuildingTestGenerated extends AbstractFirCfgBuildingTest {
|
||||
runTest("compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inPlaceLambdas.kt")
|
||||
public void testInPlaceLambdas() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/smartcasts/inPlaceLambdas.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullability.kt")
|
||||
public void testNullability() throws Exception {
|
||||
runTest("compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt");
|
||||
|
||||
Reference in New Issue
Block a user