[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 enterFunction(function: FirFunction<*>) {}
|
||||||
|
|
||||||
override fun exitFunction(function: FirFunction<*>): ControlFlowGraph = ControlFlowGraph(DUMMY)
|
override fun exitFunction(function: FirFunction<*>): ControlFlowGraph? = null
|
||||||
|
|
||||||
override fun enterBlock(block: FirBlock) {}
|
override fun enterBlock(block: FirBlock) {}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ abstract class FirDataFlowAnalyzer {
|
|||||||
// ----------------------------------- Named function -----------------------------------
|
// ----------------------------------- Named function -----------------------------------
|
||||||
|
|
||||||
abstract fun enterFunction(function: FirFunction<*>)
|
abstract fun enterFunction(function: FirFunction<*>)
|
||||||
abstract fun exitFunction(function: FirFunction<*>): ControlFlowGraph
|
abstract fun exitFunction(function: FirFunction<*>): ControlFlowGraph?
|
||||||
|
|
||||||
// ----------------------------------- Property -----------------------------------
|
// ----------------------------------- 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)
|
val (node, graph) = graphBuilder.exitFunction(function)
|
||||||
node.passFlow()
|
node.passFlow()
|
||||||
for (valueParameter in function.valueParameters) {
|
for (valueParameter in function.valueParameters) {
|
||||||
|
|||||||
+51
-8
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve.dfa.cfg
|
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.FirElement
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirAbstractPropertyAccessor
|
import org.jetbrains.kotlin.fir.declarations.impl.FirAbstractPropertyAccessor
|
||||||
@@ -65,18 +66,48 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() {
|
|||||||
is FirConstructor -> function.name.asString()
|
is FirConstructor -> function.name.asString()
|
||||||
else -> throw IllegalArgumentException("Unknown function: ${function.render()}")
|
else -> throw IllegalArgumentException("Unknown function: ${function.render()}")
|
||||||
}
|
}
|
||||||
graphs.push(ControlFlowGraph(name))
|
val invocationKind = function.invocationKind
|
||||||
functionExitNodes.push(createFunctionExitNode(function))
|
val isInplace = invocationKind.isInplace()
|
||||||
lexicalScopes.push(stackOf())
|
if (!isInplace) {
|
||||||
return createFunctionEnterNode(function).also { lastNodes.push(it) }.also { levelCounter++ }
|
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--
|
levelCounter--
|
||||||
val exitNode = functionExitNodes.pop()
|
val exitNode = functionExitNodes.pop()
|
||||||
addEdge(lastNodes.pop(), exitNode)
|
val isInplace = function.isInplace()
|
||||||
lexicalScopes.pop()
|
if (isInplace) {
|
||||||
return exitNode to graphs.pop()
|
addNewSimpleNode(exitNode)
|
||||||
|
} else {
|
||||||
|
addEdge(lastNodes.pop(), exitNode)
|
||||||
|
lexicalScopes.pop()
|
||||||
|
}
|
||||||
|
val graph = if (!isInplace) {
|
||||||
|
graphs.pop()
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
return exitNode to graph
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------- Block -----------------------------------
|
// ----------------------------------- Block -----------------------------------
|
||||||
@@ -503,4 +534,16 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() {
|
|||||||
from.followingNodes += to
|
from.followingNodes += to
|
||||||
to.previousNodes += from
|
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 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 {
|
FunctionEnterNode(graph, fir, levelCounter).also {
|
||||||
graph.enterNode = it
|
if (!isInPlace) {
|
||||||
|
graph.enterNode = it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun createFunctionExitNode(fir: FirFunction<*>): FunctionExitNode = FunctionExitNode(graph, fir, levelCounter).also {
|
protected fun createFunctionExitNode(fir: FirFunction<*>, isInPlace: Boolean): FunctionExitNode =
|
||||||
graph.exitNode = it
|
FunctionExitNode(graph, fir, levelCounter).also {
|
||||||
|
if (!isInPlace) {
|
||||||
|
graph.exitNode = it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun createBinaryOrEnterNode(fir: FirBinaryLogicExpression): BinaryOrEnterNode =
|
protected fun createBinaryOrEnterNode(fir: FirBinaryLogicExpression): BinaryOrEnterNode =
|
||||||
|
|||||||
+3
-2
@@ -603,8 +603,9 @@ open class FirBodyResolveTransformer(
|
|||||||
dataFlowAnalyzer.enterFunction(function)
|
dataFlowAnalyzer.enterFunction(function)
|
||||||
super.transformFunction(function, data).also {
|
super.transformFunction(function, data).also {
|
||||||
val result = it.single as FirFunction<*>
|
val result = it.single as FirFunction<*>
|
||||||
val controlFlowGraph = dataFlowAnalyzer.exitFunction(result)
|
dataFlowAnalyzer.exitFunction(result)?.let { controlFlowGraph ->
|
||||||
result.transformControlFlowGraphReference(ControlFlowGraphReferenceTransformer, 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?`| {
|
@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 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 {
|
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#)
|
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| {
|
public set(value: R|kotlin/Int|): R|kotlin/Unit| {
|
||||||
F|/x2| = Int(1)
|
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| {
|
local final fun foo(): R|kotlin/Unit| {
|
||||||
lval c: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(1))
|
lval c: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(1))
|
||||||
throw <Ambiguity: Exception, [java/lang/Exception.Exception, java/lang/Exception.Exception]>#()
|
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");
|
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")
|
@TestMetadata("loops.kt")
|
||||||
public void testLoops() throws Exception {
|
public void testLoops() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/cfg/loops.kt");
|
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");
|
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")
|
@TestMetadata("nullability.kt")
|
||||||
public void testNullability() throws Exception {
|
public void testNullability() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt");
|
runTest("compiler/fir/resolve/testData/resolve/smartcasts/nullability.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user