[FIR] Add processing of loops with constant boolean value in condition

This commit is contained in:
Dmitriy Novozhilov
2019-08-27 16:13:17 +03:00
parent a60115c452
commit b2e95eebab
14 changed files with 1158 additions and 70 deletions
@@ -74,8 +74,8 @@ class WhenBranchResultExitNode(owner: ControlFlowGraph, override val fir: FirWhe
class LoopEnterNode(owner: ControlFlowGraph, override val fir: FirLoop, level: Int) : CFGNode<FirLoop>(owner, level)
class LoopBlockEnterNode(owner: ControlFlowGraph, override val fir: FirLoop, level: Int) : CFGNode<FirLoop>(owner, level)
class LoopBlockExitNode(owner: ControlFlowGraph, override val fir: FirLoop, level: Int) : CFGNode<FirLoop>(owner, level)
class LoopConditionEnterNode(owner: ControlFlowGraph, override val fir: FirLoop, level: Int) : CFGNode<FirLoop>(owner, level)
class LoopConditionExitNode(owner: ControlFlowGraph, override val fir: FirLoop, level: Int) : CFGNode<FirLoop>(owner, level)
class LoopConditionEnterNode(owner: ControlFlowGraph, override val fir: FirExpression, level: Int) : CFGNode<FirExpression>(owner, level)
class LoopConditionExitNode(owner: ControlFlowGraph, override val fir: FirExpression, level: Int) : CFGNode<FirExpression>(owner, level)
class LoopExitNode(owner: ControlFlowGraph, override val fir: FirLoop, level: Int) : CFGNode<FirLoop>(owner, level)
// ----------------------------------- Try-catch-finally -----------------------------------
@@ -217,7 +217,7 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() {
addNewSimpleNode(createLoopEnterNode(loop))
loopExitNodes.push(createLoopExitNode(loop))
levelCounter++
val node = createLoopConditionEnterNode(loop)
val node = createLoopConditionEnterNode(loop.condition)
levelCounter++
addNewSimpleNode(node)
// put conditional node twice so we can refer it after exit from loop block
@@ -228,11 +228,12 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() {
fun exitWhileLoopCondition(loop: FirLoop): LoopConditionExitNode {
levelCounter--
val conditionExitNode = createLoopConditionExitNode(loop)
val conditionExitNode = createLoopConditionExitNode(loop.condition)
addNewSimpleNode(conditionExitNode)
// TODO: here we can check that condition is always true
addEdge(conditionExitNode, loopExitNodes.top())
addNewSimpleNode(createLoopBlockEnterNode(loop))
val conditionConstBooleanValue = conditionExitNode.booleanConstValue
addEdge(conditionExitNode, loopExitNodes.top(), isDead = conditionConstBooleanValue == true)
val loopBlockEnterNode = createLoopBlockEnterNode(loop)
addNewSimpleNode(loopBlockEnterNode, conditionConstBooleanValue == false)
levelCounter++
return conditionExitNode
}
@@ -272,7 +273,7 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() {
fun enterDoWhileLoopCondition(loop: FirLoop): Pair<LoopBlockExitNode, LoopConditionEnterNode> {
levelCounter--
val blockExitNode = createLoopBlockExitNode(loop).also { addNewSimpleNode(it) }
val conditionEnterNode = createLoopConditionEnterNode(loop).also { addNewSimpleNode(it) }
val conditionEnterNode = createLoopConditionEnterNode(loop.condition).also { addNewSimpleNode(it) }
levelCounter++
return blockExitNode to conditionEnterNode
}
@@ -280,14 +281,14 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() {
fun exitDoWhileLoop(loop: FirLoop): LoopExitNode {
loopEnterNodes.pop()
levelCounter--
val conditionExitNode = createLoopConditionExitNode(loop)
// TODO: here we can check that condition is always false
val conditionExitNode = createLoopConditionExitNode(loop.condition)
val conditionBooleanValue = conditionExitNode.booleanConstValue
addEdge(lastNodes.pop(), conditionExitNode)
val blockEnterNode = lastNodes.pop()
require(blockEnterNode is LoopBlockEnterNode)
addEdge(conditionExitNode, blockEnterNode, propagateDeadness = false)
addEdge(conditionExitNode, blockEnterNode, propagateDeadness = false, isDead = conditionBooleanValue == false)
val loopExit = loopExitNodes.pop()
addEdge(conditionExitNode, loopExit, propagateDeadness = false)
addEdge(conditionExitNode, loopExit, propagateDeadness = false, isDead = conditionBooleanValue == true)
loopExit.markAsDeadIfNecessary()
lastNodes.push(loopExit)
levelCounter--
@@ -531,22 +532,22 @@ class ControlFlowGraphBuilder : ControlFlowGraphNodeBuilder() {
lastNodes.push(stub)
}
private fun addNewSimpleNode(newNode: CFGNode<*>): CFGNode<*> {
private fun addNewSimpleNode(newNode: CFGNode<*>, isDead: Boolean = false): CFGNode<*> {
val oldNode = lastNodes.pop()
addEdge(oldNode, newNode)
addEdge(oldNode, newNode, isDead = isDead)
lastNodes.push(newNode)
return oldNode
}
private fun addDeadEdge(from: CFGNode<*>, to: CFGNode<*>) {
private fun addDeadEdge(from: CFGNode<*>, to: CFGNode<*>, propagateDeadness: Boolean) {
val stub = createStubNode()
addEdge(from, stub)
addEdge(stub, to)
addEdge(stub, to, propagateDeadness = propagateDeadness)
}
private fun addEdge(from: CFGNode<*>, to: CFGNode<*>, propagateDeadness: Boolean = true, isDead: Boolean = false) {
if (isDead) {
addDeadEdge(from, to)
addDeadEdge(from, to, propagateDeadness)
return
}
if (propagateDeadness && from.isDead) {
@@ -95,10 +95,10 @@ abstract class ControlFlowGraphNodeBuilder {
protected fun createWhenBranchResultExitNode(fir: FirWhenBranch): WhenBranchResultExitNode =
WhenBranchResultExitNode(graph, fir, levelCounter)
protected fun createLoopConditionExitNode(fir: FirLoop): LoopConditionExitNode =
protected fun createLoopConditionExitNode(fir: FirExpression): LoopConditionExitNode =
LoopConditionExitNode(graph, fir, levelCounter)
protected fun createLoopConditionEnterNode(fir: FirLoop): LoopConditionEnterNode =
protected fun createLoopConditionEnterNode(fir: FirExpression): LoopConditionEnterNode =
LoopConditionEnterNode(graph, fir, levelCounter)
protected fun createLoopBlockEnterNode(fir: FirLoop): LoopBlockEnterNode =
+38 -33
View File
@@ -121,73 +121,78 @@ subgraph test_3 {
61 [shape=box label="Stub[DEAD]"];
62 [shape=box label="Exit block[DEAD]"];
63 [shape=box label="Exit loop block[DEAD]"];
64 [shape=box label="Exit whileloop"];
65 [shape=box label="Access variable R|<local>/x|"];
66 [shape=box label="Function call: R|<local>/x|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()"];
67 [shape=box label="Exit block"];
68 [shape=box label="Exit function test_3"];
64 [shape=box label="Stub[DEAD]"];
65 [shape=box label="Exit whileloop"];
66 [shape=box label="Access variable R|<local>/x|"];
67 [shape=box label="Function call: R|<local>/x|.R|kotlin/Int.inc|()"];
68 [shape=box label="Exit block"];
69 [shape=box label="Exit function test_3"];
50 -> {51};
51 -> {52};
52 -> {53};
53 -> {54};
54 -> {55};
55 -> {64 56};
55 -> {56};
55 -> {64} [style=dotted];
56 -> {57};
57 -> {58};
58 -> {59};
59 -> {60};
60 -> {64};
60 -> {65};
60 -> {61} [style=dotted];
61 -> {62} [style=dotted];
62 -> {63} [style=dotted];
63 -> {53} [style=dotted];
64 -> {65};
64 -> {65} [style=dotted];
65 -> {66};
66 -> {67};
67 -> {68};
68 -> {69};
}
subgraph test_4 {
69 [shape=box label="Enter function test_4"];
70 [shape=box label="Enter block"];
71 [shape=box label="Enter do-while loop"];
72 [shape=box label="Enter loop block"];
73 [shape=box label="Enter block"];
74 [shape=box label="Access variable R|<local>/x|"];
75 [shape=box label="Type operator: x as int"];
76 [shape=box label="Jump: break@@@[Boolean(true)] "];
77 [shape=box label="Stub[DEAD]"];
78 [shape=box label="Exit block[DEAD]"];
79 [shape=box label="Exit loop block[DEAD]"];
80 [shape=box label="Enter loop condition[DEAD]"];
81 [shape=box label="Const: Boolean(true)[DEAD]"];
82 [shape=box label="Exit loop condition[DEAD]"];
83 [shape=box label="Exit do-whileloop"];
84 [shape=box label="Access variable R|<local>/x|"];
85 [shape=box label="Function call: R|<local>/x|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()"];
86 [shape=box label="Exit block"];
87 [shape=box label="Exit function test_4"];
70 [shape=box label="Enter function test_4"];
71 [shape=box label="Enter block"];
72 [shape=box label="Enter do-while loop"];
73 [shape=box label="Enter loop block"];
74 [shape=box label="Enter block"];
75 [shape=box label="Access variable R|<local>/x|"];
76 [shape=box label="Type operator: x as Int"];
77 [shape=box label="Jump: break@@@[Boolean(true)] "];
78 [shape=box label="Stub[DEAD]"];
79 [shape=box label="Exit block[DEAD]"];
80 [shape=box label="Exit loop block[DEAD]"];
81 [shape=box label="Enter loop condition[DEAD]"];
82 [shape=box label="Const: Boolean(true)[DEAD]"];
83 [shape=box label="Exit loop condition[DEAD]"];
84 [shape=box label="Stub[DEAD]"];
85 [shape=box label="Exit do-whileloop"];
86 [shape=box label="Access variable R|<local>/x|"];
87 [shape=box label="Function call: R|<local>/x|.R|kotlin/Int.inc|()"];
88 [shape=box label="Exit block"];
89 [shape=box label="Exit function test_4"];
69 -> {70};
70 -> {71};
71 -> {72};
72 -> {73};
73 -> {74};
74 -> {75};
75 -> {76};
76 -> {83};
76 -> {77} [style=dotted];
76 -> {77};
77 -> {85};
77 -> {78} [style=dotted];
78 -> {79} [style=dotted];
79 -> {80} [style=dotted];
80 -> {81} [style=dotted];
81 -> {82} [style=dotted];
82 -> {72 83} [style=dotted];
83 -> {84};
84 -> {85};
82 -> {83} [style=dotted];
83 -> {73 84} [style=dotted];
84 -> {85} [style=dotted];
85 -> {86};
86 -> {87};
87 -> {88};
88 -> {89};
}
}
+1 -1
View File
@@ -26,7 +26,7 @@ fun test_3(x: Int?) {
fun test_4(x: Int?) {
do {
x as int
x as Int
break
} while (true)
x.inc()
+3 -3
View File
@@ -29,13 +29,13 @@ FILE: jumps.kt
break@@@[Boolean(true)]
}
R|<local>/x|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()
R|<local>/x|.R|kotlin/Int.inc|()
}
public final fun test_4(x: R|kotlin/Int?|): R|kotlin/Unit| {
do {
(R|<local>/x| as R|class error: Symbol not found, for `int`|)
(R|<local>/x| as R|kotlin/Int|)
break@@@[Boolean(true)]
}
while(Boolean(true))
R|<local>/x|.<Ambiguity: inc, [kotlin/inc, kotlin/inc]>#()
R|<local>/x|.R|kotlin/Int.inc|()
}
+274
View File
@@ -138,4 +138,278 @@ subgraph testFor {
63 -> {64};
}
subgraph testWhileTrue {
65 [shape=box label="Enter function testWhileTrue"];
66 [shape=box label="Enter block"];
67 [shape=box label="Enter while loop"];
68 [shape=box label="Enter loop condition"];
69 [shape=box label="Const: Boolean(true)"];
70 [shape=box label="Exit loop condition"];
71 [shape=box label="Enter loop block"];
72 [shape=box label="Enter block"];
73 [shape=box label="Const: Int(1)"];
74 [shape=box label="Exit block"];
75 [shape=box label="Exit loop block"];
76 [shape=box label="Stub[DEAD]"];
77 [shape=box label="Exit whileloop[DEAD]"];
78 [shape=box label="Const: Int(1)[DEAD]"];
79 [shape=box label="Exit block[DEAD]"];
80 [shape=box label="Exit function testWhileTrue[DEAD]"];
65 -> {66};
66 -> {67};
67 -> {68};
68 -> {69};
69 -> {70};
70 -> {71};
70 -> {76} [style=dotted];
71 -> {72};
72 -> {73};
73 -> {74};
74 -> {75};
75 -> {68};
76 -> {77} [style=dotted];
77 -> {78} [style=dotted];
78 -> {79} [style=dotted];
79 -> {80} [style=dotted];
}
subgraph testWhileTrueWithBreak {
81 [shape=box label="Enter function testWhileTrueWithBreak"];
82 [shape=box label="Enter block"];
83 [shape=box label="Enter while loop"];
84 [shape=box label="Enter loop condition"];
85 [shape=box label="Const: Boolean(true)"];
86 [shape=box label="Exit loop condition"];
87 [shape=box label="Enter loop block"];
88 [shape=box label="Enter block"];
89 [shape=box label="Enter when"];
90 [shape=box label="Enter when branch condition "];
91 [shape=box label="Access variable R|<local>/b|"];
92 [shape=box label="Exit when branch condition"];
93 [shape=box label="Enter block"];
94 [shape=box label="Jump: break@@@[Boolean(true)] "];
95 [shape=box label="Stub[DEAD]"];
96 [shape=box label="Exit block[DEAD]"];
97 [shape=box label="Exit when branch result[DEAD]"];
98 [shape=box label="Enter when branch condition else"];
99 [shape=box label="Exit when branch condition"];
100 [shape=box label="Enter block"];
101 [shape=box label="Exit block"];
102 [shape=box label="Exit when branch result"];
103 [shape=box label="Exit when"];
104 [shape=box label="Exit block"];
105 [shape=box label="Exit loop block"];
106 [shape=box label="Stub[DEAD]"];
107 [shape=box label="Exit whileloop"];
108 [shape=box label="Const: Int(1)"];
109 [shape=box label="Exit block"];
110 [shape=box label="Exit function testWhileTrueWithBreak"];
81 -> {82};
82 -> {83};
83 -> {84};
84 -> {85};
85 -> {86};
86 -> {87};
86 -> {106} [style=dotted];
87 -> {88};
88 -> {89};
89 -> {90};
90 -> {91};
91 -> {92};
92 -> {93 98};
93 -> {94};
94 -> {107};
94 -> {95} [style=dotted];
95 -> {96} [style=dotted];
96 -> {97} [style=dotted];
97 -> {103} [style=dotted];
98 -> {99};
99 -> {100};
100 -> {101};
101 -> {102};
102 -> {103};
103 -> {104};
104 -> {105};
105 -> {84};
106 -> {107} [style=dotted];
107 -> {108};
108 -> {109};
109 -> {110};
}
subgraph testWhileFalse {
111 [shape=box label="Enter function testWhileFalse"];
112 [shape=box label="Enter block"];
113 [shape=box label="Enter while loop"];
114 [shape=box label="Enter loop condition"];
115 [shape=box label="Const: Boolean(false)"];
116 [shape=box label="Exit loop condition"];
117 [shape=box label="Stub[DEAD]"];
118 [shape=box label="Enter loop block[DEAD]"];
119 [shape=box label="Enter block[DEAD]"];
120 [shape=box label="Const: Int(1)[DEAD]"];
121 [shape=box label="Exit block[DEAD]"];
122 [shape=box label="Exit loop block[DEAD]"];
123 [shape=box label="Exit whileloop"];
124 [shape=box label="Const: Int(1)"];
125 [shape=box label="Exit block"];
126 [shape=box label="Exit function testWhileFalse"];
111 -> {112};
112 -> {113};
113 -> {114};
114 -> {115};
115 -> {116};
116 -> {123};
116 -> {117} [style=dotted];
117 -> {118} [style=dotted];
118 -> {119} [style=dotted];
119 -> {120} [style=dotted];
120 -> {121} [style=dotted];
121 -> {122} [style=dotted];
122 -> {114} [style=dotted];
123 -> {124};
124 -> {125};
125 -> {126};
}
subgraph testDoWhileTrue {
127 [shape=box label="Enter function testDoWhileTrue"];
128 [shape=box label="Enter block"];
129 [shape=box label="Enter do-while loop"];
130 [shape=box label="Enter loop block"];
131 [shape=box label="Enter block"];
132 [shape=box label="Const: Int(1)"];
133 [shape=box label="Exit block"];
134 [shape=box label="Exit loop block"];
135 [shape=box label="Enter loop condition"];
136 [shape=box label="Const: Boolean(true)"];
137 [shape=box label="Exit loop condition"];
138 [shape=box label="Stub[DEAD]"];
139 [shape=box label="Exit do-whileloop[DEAD]"];
140 [shape=box label="Const: Int(1)[DEAD]"];
141 [shape=box label="Exit block[DEAD]"];
142 [shape=box label="Exit function testDoWhileTrue[DEAD]"];
127 -> {128};
128 -> {129};
129 -> {130};
130 -> {131};
131 -> {132};
132 -> {133};
133 -> {134};
134 -> {135};
135 -> {136};
136 -> {137};
137 -> {130};
137 -> {138} [style=dotted];
138 -> {139} [style=dotted];
139 -> {140} [style=dotted];
140 -> {141} [style=dotted];
141 -> {142} [style=dotted];
}
subgraph testDoWhileTrueWithBreak {
143 [shape=box label="Enter function testDoWhileTrueWithBreak"];
144 [shape=box label="Enter block"];
145 [shape=box label="Enter do-while loop"];
146 [shape=box label="Enter loop block"];
147 [shape=box label="Enter block"];
148 [shape=box label="Enter when"];
149 [shape=box label="Enter when branch condition "];
150 [shape=box label="Access variable R|<local>/b|"];
151 [shape=box label="Exit when branch condition"];
152 [shape=box label="Enter block"];
153 [shape=box label="Jump: break@@@[Boolean(true)] "];
154 [shape=box label="Stub[DEAD]"];
155 [shape=box label="Exit block[DEAD]"];
156 [shape=box label="Exit when branch result[DEAD]"];
157 [shape=box label="Enter when branch condition else"];
158 [shape=box label="Exit when branch condition"];
159 [shape=box label="Enter block"];
160 [shape=box label="Exit block"];
161 [shape=box label="Exit when branch result"];
162 [shape=box label="Exit when"];
163 [shape=box label="Exit block"];
164 [shape=box label="Exit loop block"];
165 [shape=box label="Enter loop condition"];
166 [shape=box label="Const: Boolean(true)"];
167 [shape=box label="Exit loop condition"];
168 [shape=box label="Stub[DEAD]"];
169 [shape=box label="Exit do-whileloop"];
170 [shape=box label="Const: Int(1)"];
171 [shape=box label="Exit block"];
172 [shape=box label="Exit function testDoWhileTrueWithBreak"];
143 -> {144};
144 -> {145};
145 -> {146};
146 -> {147};
147 -> {148};
148 -> {149};
149 -> {150};
150 -> {151};
151 -> {152 157};
152 -> {153};
153 -> {169};
153 -> {154} [style=dotted];
154 -> {155} [style=dotted];
155 -> {156} [style=dotted];
156 -> {162} [style=dotted];
157 -> {158};
158 -> {159};
159 -> {160};
160 -> {161};
161 -> {162};
162 -> {163};
163 -> {164};
164 -> {165};
165 -> {166};
166 -> {167};
167 -> {146};
167 -> {168} [style=dotted];
168 -> {169} [style=dotted];
169 -> {170};
170 -> {171};
171 -> {172};
}
subgraph testDoWhileFalse {
173 [shape=box label="Enter function testDoWhileFalse"];
174 [shape=box label="Enter block"];
175 [shape=box label="Enter do-while loop"];
176 [shape=box label="Enter loop block"];
177 [shape=box label="Enter block"];
178 [shape=box label="Const: Int(1)"];
179 [shape=box label="Exit block"];
180 [shape=box label="Exit loop block"];
181 [shape=box label="Enter loop condition"];
182 [shape=box label="Const: Boolean(false)"];
183 [shape=box label="Exit loop condition"];
184 [shape=box label="Exit do-whileloop"];
185 [shape=box label="Const: Int(1)"];
186 [shape=box label="Exit block"];
187 [shape=box label="Exit function testDoWhileFalse"];
188 [shape=box label="Stub[DEAD]"];
173 -> {174};
174 -> {175};
175 -> {176};
176 -> {177};
177 -> {178};
178 -> {179};
179 -> {180};
180 -> {181};
181 -> {182};
182 -> {183};
183 -> {184};
183 -> {188} [style=dotted];
184 -> {185};
185 -> {186};
186 -> {187};
188 -> {176} [style=dotted];
}
}
+47
View File
@@ -17,4 +17,51 @@ fun testFor(x: Any?) {
val y = x is String
}
x is String
}
fun testWhileTrue() {
while (true) {
1
}
1
}
fun testWhileTrueWithBreak(b: Boolean) {
while (true) {
if (b) {
break
}
}
1
}
fun testWhileFalse() {
while (false) {
1
}
1
}
fun testDoWhileTrue() {
do {
1
} while (true)
1
}
fun testDoWhileTrueWithBreak(b: Boolean) {
do {
if (b) {
break
}
} while (true)
1
}
fun testDoWhileFalse() {
do {
1
} while (false)
1
}
+56
View File
@@ -23,3 +23,59 @@ FILE: loops.kt
(R|<local>/x| is R|kotlin/String|)
}
public final fun testWhileTrue(): R|kotlin/Unit| {
while(Boolean(true)) {
Int(1)
}
Int(1)
}
public final fun testWhileTrueWithBreak(b: R|kotlin/Boolean|): R|kotlin/Unit| {
while(Boolean(true)) {
when () {
R|<local>/b| -> {
break@@@[Boolean(true)]
}
else -> {
}
}
}
Int(1)
}
public final fun testWhileFalse(): R|kotlin/Unit| {
while(Boolean(false)) {
Int(1)
}
Int(1)
}
public final fun testDoWhileTrue(): R|kotlin/Unit| {
do {
Int(1)
}
while(Boolean(true))
Int(1)
}
public final fun testDoWhileTrueWithBreak(b: R|kotlin/Boolean|): R|kotlin/Unit| {
do {
when () {
R|<local>/b| -> {
break@@@[Boolean(true)]
}
else -> {
}
}
}
while(Boolean(true))
Int(1)
}
public final fun testDoWhileFalse(): R|kotlin/Unit| {
do {
Int(1)
}
while(Boolean(false))
Int(1)
}
+16 -14
View File
@@ -151,29 +151,31 @@ subgraph test_3 {
101 [shape=box label="Variable declaration: lval y: R|kotlin/Int|"];
102 [shape=box label="Exit block"];
103 [shape=box label="Exit loop block"];
104 [shape=box label="Exit whileloop"];
105 [shape=box label="Const: Int(3)"];
106 [shape=box label="Variable declaration: lval z: R|kotlin/Int|"];
107 [shape=box label="Exit block"];
108 [shape=box label="Exit function test_3"];
104 [shape=box label="Stub[DEAD]"];
105 [shape=box label="Exit whileloop"];
106 [shape=box label="Const: Int(3)"];
107 [shape=box label="Variable declaration: lval z: R|kotlin/Int|"];
108 [shape=box label="Exit block"];
109 [shape=box label="Exit function test_3"];
41 -> {42};
42 -> {43};
43 -> {44};
44 -> {45};
45 -> {46};
46 -> {104 47};
46 -> {47};
46 -> {104} [style=dotted];
47 -> {48};
48 -> {49};
49 -> {50};
50 -> {108 93 87 51};
50 -> {109 93 87 51};
51 -> {52};
52 -> {53};
53 -> {54};
54 -> {55};
55 -> {56 61};
56 -> {57};
57 -> {108};
57 -> {109};
57 -> {58} [style=dotted];
58 -> {59} [style=dotted];
59 -> {60} [style=dotted];
@@ -192,7 +194,7 @@ subgraph test_3 {
72 -> {73};
73 -> {74 79};
74 -> {75};
75 -> {104};
75 -> {105};
75 -> {76} [style=dotted];
76 -> {77} [style=dotted];
77 -> {78} [style=dotted];
@@ -205,16 +207,15 @@ subgraph test_3 {
84 -> {85};
85 -> {86};
86 -> {99};
87 -> {108 88};
87 -> {109 88};
88 -> {89};
89 -> {104};
89 -> {105};
89 -> {90} [style=dotted];
90 -> {91} [style=dotted];
91 -> {92} [style=dotted];
92 -> {99} [style=dotted];
93 -> {108 94};
93 -> {109 94};
94 -> {95};
95 -> {44};
95 -> {96} [style=dotted];
96 -> {97} [style=dotted];
97 -> {98} [style=dotted];
@@ -224,10 +225,11 @@ subgraph test_3 {
101 -> {102};
102 -> {103};
103 -> {44};
104 -> {105};
104 -> {105} [style=dotted];
105 -> {106};
106 -> {107};
107 -> {108};
108 -> {109};
}
}
@@ -0,0 +1,513 @@
digraph endlessLoops_kt {
graph [splines=ortho]
subgraph foo {
0 [shape=box label="Enter function foo"];
1 [shape=box label="Exit function foo"];
0 -> {1};
}
subgraph test_1 {
2 [shape=box label="Enter function test_1"];
3 [shape=box label="Enter block"];
4 [shape=box label="Enter while loop"];
5 [shape=box label="Enter loop condition"];
6 [shape=box label="Const: Boolean(true)"];
7 [shape=box label="Exit loop condition"];
8 [shape=box label="Enter loop block"];
9 [shape=box label="Enter block"];
10 [shape=box label="Access variable R|<local>/x|"];
11 [shape=box label="Type operator: x as A"];
12 [shape=box label="Enter when"];
13 [shape=box label="Enter when branch condition "];
14 [shape=box label="Access variable R|<local>/b|"];
15 [shape=box label="Exit when branch condition"];
16 [shape=box label="Enter block"];
17 [shape=box label="Jump: break@@@[Boolean(true)] "];
18 [shape=box label="Stub[DEAD]"];
19 [shape=box label="Exit block[DEAD]"];
20 [shape=box label="Exit when branch result[DEAD]"];
21 [shape=box label="Enter when branch condition else"];
22 [shape=box label="Exit when branch condition"];
23 [shape=box label="Enter block"];
24 [shape=box label="Exit block"];
25 [shape=box label="Exit when branch result"];
26 [shape=box label="Exit when"];
27 [shape=box label="Exit block"];
28 [shape=box label="Exit loop block"];
29 [shape=box label="Stub[DEAD]"];
30 [shape=box label="Exit whileloop"];
31 [shape=box label="Access variable R|<local>/x|"];
32 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
33 [shape=box label="Exit block"];
34 [shape=box label="Exit function test_1"];
2 -> {3};
3 -> {4};
4 -> {5};
5 -> {6};
6 -> {7};
7 -> {8};
7 -> {29} [style=dotted];
8 -> {9};
9 -> {10};
10 -> {11};
11 -> {12};
12 -> {13};
13 -> {14};
14 -> {15};
15 -> {16 21};
16 -> {17};
17 -> {30};
17 -> {18} [style=dotted];
18 -> {19} [style=dotted];
19 -> {20} [style=dotted];
20 -> {26} [style=dotted];
21 -> {22};
22 -> {23};
23 -> {24};
24 -> {25};
25 -> {26};
26 -> {27};
27 -> {28};
28 -> {5};
29 -> {30} [style=dotted];
30 -> {31};
31 -> {32};
32 -> {33};
33 -> {34};
}
subgraph test_2 {
35 [shape=box label="Enter function test_2"];
36 [shape=box label="Enter block"];
37 [shape=box label="Enter while loop"];
38 [shape=box label="Enter loop condition"];
39 [shape=box label="Const: Boolean(true)"];
40 [shape=box label="Exit loop condition"];
41 [shape=box label="Enter loop block"];
42 [shape=box label="Enter block"];
43 [shape=box label="Enter when"];
44 [shape=box label="Enter when branch condition "];
45 [shape=box label="Access variable R|<local>/b|"];
46 [shape=box label="Exit when branch condition"];
47 [shape=box label="Enter block"];
48 [shape=box label="Access variable R|<local>/x|"];
49 [shape=box label="Type operator: x as A"];
50 [shape=box label="Jump: break@@@[Boolean(true)] "];
51 [shape=box label="Stub[DEAD]"];
52 [shape=box label="Exit block[DEAD]"];
53 [shape=box label="Exit when branch result[DEAD]"];
54 [shape=box label="Enter when branch condition else"];
55 [shape=box label="Exit when branch condition"];
56 [shape=box label="Enter block"];
57 [shape=box label="Exit block"];
58 [shape=box label="Exit when branch result"];
59 [shape=box label="Exit when"];
60 [shape=box label="Exit block"];
61 [shape=box label="Exit loop block"];
62 [shape=box label="Stub[DEAD]"];
63 [shape=box label="Exit whileloop"];
64 [shape=box label="Access variable R|<local>/x|"];
65 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
66 [shape=box label="Exit block"];
67 [shape=box label="Exit function test_2"];
35 -> {36};
36 -> {37};
37 -> {38};
38 -> {39};
39 -> {40};
40 -> {41};
40 -> {62} [style=dotted];
41 -> {42};
42 -> {43};
43 -> {44};
44 -> {45};
45 -> {46};
46 -> {47 54};
47 -> {48};
48 -> {49};
49 -> {50};
50 -> {63};
50 -> {51} [style=dotted];
51 -> {52} [style=dotted];
52 -> {53} [style=dotted];
53 -> {59} [style=dotted];
54 -> {55};
55 -> {56};
56 -> {57};
57 -> {58};
58 -> {59};
59 -> {60};
60 -> {61};
61 -> {38};
62 -> {63} [style=dotted];
63 -> {64};
64 -> {65};
65 -> {66};
66 -> {67};
}
subgraph test_3 {
68 [shape=box label="Enter function test_3"];
69 [shape=box label="Enter block"];
70 [shape=box label="Enter while loop"];
71 [shape=box label="Enter loop condition"];
72 [shape=box label="Const: Boolean(true)"];
73 [shape=box label="Exit loop condition"];
74 [shape=box label="Enter loop block"];
75 [shape=box label="Enter block"];
76 [shape=box label="Access variable R|<local>/x|"];
77 [shape=box label="Type operator: x as A"];
78 [shape=box label="Enter when"];
79 [shape=box label="Enter when branch condition "];
80 [shape=box label="Access variable R|<local>/b|"];
81 [shape=box label="Exit when branch condition"];
82 [shape=box label="Enter block"];
83 [shape=box label="Jump: break@@@[Boolean(true)] "];
84 [shape=box label="Stub[DEAD]"];
85 [shape=box label="Exit block[DEAD]"];
86 [shape=box label="Exit when branch result[DEAD]"];
87 [shape=box label="Enter when branch condition else"];
88 [shape=box label="Exit when branch condition"];
89 [shape=box label="Enter block"];
90 [shape=box label="Exit block"];
91 [shape=box label="Exit when branch result"];
92 [shape=box label="Exit when"];
93 [shape=box label="Enter when"];
94 [shape=box label="Enter when branch condition "];
95 [shape=box label="Access variable R|<local>/b|"];
96 [shape=box label="Exit when branch condition"];
97 [shape=box label="Enter block"];
98 [shape=box label="Jump: break@@@[Boolean(true)] "];
99 [shape=box label="Stub[DEAD]"];
100 [shape=box label="Exit block[DEAD]"];
101 [shape=box label="Exit when branch result[DEAD]"];
102 [shape=box label="Enter when branch condition else"];
103 [shape=box label="Exit when branch condition"];
104 [shape=box label="Enter block"];
105 [shape=box label="Exit block"];
106 [shape=box label="Exit when branch result"];
107 [shape=box label="Exit when"];
108 [shape=box label="Exit block"];
109 [shape=box label="Exit loop block"];
110 [shape=box label="Stub[DEAD]"];
111 [shape=box label="Exit whileloop"];
112 [shape=box label="Access variable R|<local>/x|"];
113 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
114 [shape=box label="Exit block"];
115 [shape=box label="Exit function test_3"];
68 -> {69};
69 -> {70};
70 -> {71};
71 -> {72};
72 -> {73};
73 -> {74};
73 -> {110} [style=dotted];
74 -> {75};
75 -> {76};
76 -> {77};
77 -> {78};
78 -> {79};
79 -> {80};
80 -> {81};
81 -> {82 87};
82 -> {83};
83 -> {111};
83 -> {84} [style=dotted];
84 -> {85} [style=dotted];
85 -> {86} [style=dotted];
86 -> {92} [style=dotted];
87 -> {88};
88 -> {89};
89 -> {90};
90 -> {91};
91 -> {92};
92 -> {93};
93 -> {94};
94 -> {95};
95 -> {96};
96 -> {97 102};
97 -> {98};
98 -> {111};
98 -> {99} [style=dotted];
99 -> {100} [style=dotted];
100 -> {101} [style=dotted];
101 -> {107} [style=dotted];
102 -> {103};
103 -> {104};
104 -> {105};
105 -> {106};
106 -> {107};
107 -> {108};
108 -> {109};
109 -> {71};
110 -> {111} [style=dotted];
111 -> {112};
112 -> {113};
113 -> {114};
114 -> {115};
}
subgraph test_4 {
116 [shape=box label="Enter function test_4"];
117 [shape=box label="Enter block"];
118 [shape=box label="Enter while loop"];
119 [shape=box label="Enter loop condition"];
120 [shape=box label="Const: Boolean(true)"];
121 [shape=box label="Exit loop condition"];
122 [shape=box label="Enter loop block"];
123 [shape=box label="Enter block"];
124 [shape=box label="Enter when"];
125 [shape=box label="Enter when branch condition "];
126 [shape=box label="Access variable R|<local>/b|"];
127 [shape=box label="Exit when branch condition"];
128 [shape=box label="Enter block"];
129 [shape=box label="Access variable R|<local>/x|"];
130 [shape=box label="Type operator: x as A"];
131 [shape=box label="Jump: break@@@[Boolean(true)] "];
132 [shape=box label="Stub[DEAD]"];
133 [shape=box label="Exit block[DEAD]"];
134 [shape=box label="Exit when branch result[DEAD]"];
135 [shape=box label="Enter when branch condition else"];
136 [shape=box label="Exit when branch condition"];
137 [shape=box label="Enter block"];
138 [shape=box label="Exit block"];
139 [shape=box label="Exit when branch result"];
140 [shape=box label="Exit when"];
141 [shape=box label="Jump: break@@@[Boolean(true)] "];
142 [shape=box label="Stub[DEAD]"];
143 [shape=box label="Exit block[DEAD]"];
144 [shape=box label="Exit loop block[DEAD]"];
145 [shape=box label="Stub[DEAD]"];
146 [shape=box label="Exit whileloop"];
147 [shape=box label="Access variable R|<local>/x|"];
148 [shape=box label="Function call: R|<local>/x|.<Unresolved name: foo>#()"];
149 [shape=box label="Exit block"];
150 [shape=box label="Exit function test_4"];
116 -> {117};
117 -> {118};
118 -> {119};
119 -> {120};
120 -> {121};
121 -> {122};
121 -> {145} [style=dotted];
122 -> {123};
123 -> {124};
124 -> {125};
125 -> {126};
126 -> {127};
127 -> {128 135};
128 -> {129};
129 -> {130};
130 -> {131};
131 -> {146};
131 -> {132} [style=dotted];
132 -> {133} [style=dotted];
133 -> {134} [style=dotted];
134 -> {140} [style=dotted];
135 -> {136};
136 -> {137};
137 -> {138};
138 -> {139};
139 -> {140};
140 -> {141};
141 -> {146};
141 -> {142} [style=dotted];
142 -> {143} [style=dotted];
143 -> {144} [style=dotted];
144 -> {119} [style=dotted];
145 -> {146} [style=dotted];
146 -> {147};
147 -> {148};
148 -> {149};
149 -> {150};
}
subgraph test_5 {
151 [shape=box label="Enter function test_5"];
152 [shape=box label="Enter block"];
153 [shape=box label="Enter do-while loop"];
154 [shape=box label="Enter loop block"];
155 [shape=box label="Enter block"];
156 [shape=box label="Enter when"];
157 [shape=box label="Enter when branch condition "];
158 [shape=box label="Access variable R|<local>/b|"];
159 [shape=box label="Exit when branch condition"];
160 [shape=box label="Enter block"];
161 [shape=box label="Access variable R|<local>/x|"];
162 [shape=box label="Type operator: x as A"];
163 [shape=box label="Jump: break@@@[Boolean(true)] "];
164 [shape=box label="Stub[DEAD]"];
165 [shape=box label="Exit block[DEAD]"];
166 [shape=box label="Exit when branch result[DEAD]"];
167 [shape=box label="Enter when branch condition else"];
168 [shape=box label="Exit when branch condition"];
169 [shape=box label="Enter block"];
170 [shape=box label="Exit block"];
171 [shape=box label="Exit when branch result"];
172 [shape=box label="Exit when"];
173 [shape=box label="Exit block"];
174 [shape=box label="Exit loop block"];
175 [shape=box label="Enter loop condition"];
176 [shape=box label="Const: Boolean(true)"];
177 [shape=box label="Exit loop condition"];
178 [shape=box label="Stub[DEAD]"];
179 [shape=box label="Exit do-whileloop"];
180 [shape=box label="Access variable R|<local>/x|"];
181 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
182 [shape=box label="Exit block"];
183 [shape=box label="Exit function test_5"];
151 -> {152};
152 -> {153};
153 -> {154};
154 -> {155};
155 -> {156};
156 -> {157};
157 -> {158};
158 -> {159};
159 -> {160 167};
160 -> {161};
161 -> {162};
162 -> {163};
163 -> {179};
163 -> {164} [style=dotted];
164 -> {165} [style=dotted];
165 -> {166} [style=dotted];
166 -> {172} [style=dotted];
167 -> {168};
168 -> {169};
169 -> {170};
170 -> {171};
171 -> {172};
172 -> {173};
173 -> {174};
174 -> {175};
175 -> {176};
176 -> {177};
177 -> {154};
177 -> {178} [style=dotted];
178 -> {179} [style=dotted];
179 -> {180};
180 -> {181};
181 -> {182};
182 -> {183};
}
subgraph test_6 {
184 [shape=box label="Enter function test_6"];
185 [shape=box label="Enter block"];
186 [shape=box label="Enter do-while loop"];
187 [shape=box label="Enter loop block"];
188 [shape=box label="Enter block"];
189 [shape=box label="Access variable R|<local>/x|"];
190 [shape=box label="Type operator: x as A"];
191 [shape=box label="Enter when"];
192 [shape=box label="Enter when branch condition "];
193 [shape=box label="Access variable R|<local>/b|"];
194 [shape=box label="Exit when branch condition"];
195 [shape=box label="Enter block"];
196 [shape=box label="Jump: break@@@[Boolean(true)] "];
197 [shape=box label="Stub[DEAD]"];
198 [shape=box label="Exit block[DEAD]"];
199 [shape=box label="Exit when branch result[DEAD]"];
200 [shape=box label="Enter when branch condition else"];
201 [shape=box label="Exit when branch condition"];
202 [shape=box label="Enter block"];
203 [shape=box label="Exit block"];
204 [shape=box label="Exit when branch result"];
205 [shape=box label="Exit when"];
206 [shape=box label="Exit block"];
207 [shape=box label="Exit loop block"];
208 [shape=box label="Enter loop condition"];
209 [shape=box label="Const: Boolean(true)"];
210 [shape=box label="Exit loop condition"];
211 [shape=box label="Stub[DEAD]"];
212 [shape=box label="Exit do-whileloop"];
213 [shape=box label="Access variable R|<local>/x|"];
214 [shape=box label="Function call: R|<local>/x|.R|/A.foo|()"];
215 [shape=box label="Exit block"];
216 [shape=box label="Exit function test_6"];
184 -> {185};
185 -> {186};
186 -> {187};
187 -> {188};
188 -> {189};
189 -> {190};
190 -> {191};
191 -> {192};
192 -> {193};
193 -> {194};
194 -> {195 200};
195 -> {196};
196 -> {212};
196 -> {197} [style=dotted];
197 -> {198} [style=dotted];
198 -> {199} [style=dotted];
199 -> {205} [style=dotted];
200 -> {201};
201 -> {202};
202 -> {203};
203 -> {204};
204 -> {205};
205 -> {206};
206 -> {207};
207 -> {208};
208 -> {209};
209 -> {210};
210 -> {187};
210 -> {211} [style=dotted];
211 -> {212} [style=dotted];
212 -> {213};
213 -> {214};
214 -> {215};
215 -> {216};
}
subgraph test_7 {
217 [shape=box label="Enter function test_7"];
218 [shape=box label="Enter block"];
219 [shape=box label="Enter do-while loop"];
220 [shape=box label="Enter loop block"];
221 [shape=box label="Enter block"];
222 [shape=box label="Access variable R|<local>/x|"];
223 [shape=box label="Type operator: x as A"];
224 [shape=box label="Exit block"];
225 [shape=box label="Exit loop block"];
226 [shape=box label="Enter loop condition"];
227 [shape=box label="Const: Boolean(true)"];
228 [shape=box label="Exit loop condition"];
229 [shape=box label="Stub[DEAD]"];
230 [shape=box label="Exit do-whileloop[DEAD]"];
231 [shape=box label="Access variable R|<local>/x|[DEAD]"];
232 [shape=box label="Function call: R|<local>/x|.<Unresolved name: foo>#()[DEAD]"];
233 [shape=box label="Exit block[DEAD]"];
234 [shape=box label="Exit function test_7[DEAD]"];
217 -> {218};
218 -> {219};
219 -> {220};
220 -> {221};
221 -> {222};
222 -> {223};
223 -> {224};
224 -> {225};
225 -> {226};
226 -> {227};
227 -> {228};
228 -> {220};
228 -> {229} [style=dotted];
229 -> {230} [style=dotted];
230 -> {231} [style=dotted];
231 -> {232} [style=dotted];
232 -> {233} [style=dotted];
233 -> {234} [style=dotted];
}
}
@@ -0,0 +1,74 @@
interface A {
fun foo()
}
fun test_1(x: Any, b: Boolean) {
while (true) {
x as A
if (b) {
break
}
}
x.foo()
}
fun test_2(x: Any, b: Boolean) {
while (true) {
if (b) {
x as A
break
}
}
x.foo()
}
fun test_3(x: Any, b: Boolean) {
while (true) {
x as A
if (b) {
break
}
if (b) {
break
}
}
x.foo()
}
fun test_4(x: Any, b: Boolean) {
while (true) {
if (b) {
x as A
break
}
break
}
x.foo() // No smartcast
}
fun test_5(x: Any, b: Boolean) {
do {
if (b) {
x as A
break
}
} while (true)
x.foo()
}
fun test_6(x: Any, b: Boolean) {
do {
x as A
if (b) {
break
}
} while (true)
x.foo()
}
fun test_7(x: Any) {
do {
x as A
} while (true)
x.foo() // No smartcast
}
@@ -0,0 +1,111 @@
FILE: endlessLoops.kt
public abstract interface A : R|kotlin/Any| {
public abstract fun foo(): R|kotlin/Unit|
}
public final fun test_1(x: R|kotlin/Any|, b: R|kotlin/Boolean|): R|kotlin/Unit| {
while(Boolean(true)) {
(R|<local>/x| as R|A|)
when () {
R|<local>/b| -> {
break@@@[Boolean(true)]
}
else -> {
}
}
}
R|<local>/x|.R|/A.foo|()
}
public final fun test_2(x: R|kotlin/Any|, b: R|kotlin/Boolean|): R|kotlin/Unit| {
while(Boolean(true)) {
when () {
R|<local>/b| -> {
(R|<local>/x| as R|A|)
break@@@[Boolean(true)]
}
else -> {
}
}
}
R|<local>/x|.R|/A.foo|()
}
public final fun test_3(x: R|kotlin/Any|, b: R|kotlin/Boolean|): R|kotlin/Unit| {
while(Boolean(true)) {
(R|<local>/x| as R|A|)
when () {
R|<local>/b| -> {
break@@@[Boolean(true)]
}
else -> {
}
}
when () {
R|<local>/b| -> {
break@@@[Boolean(true)]
}
else -> {
}
}
}
R|<local>/x|.R|/A.foo|()
}
public final fun test_4(x: R|kotlin/Any|, b: R|kotlin/Boolean|): R|kotlin/Unit| {
while(Boolean(true)) {
when () {
R|<local>/b| -> {
(R|<local>/x| as R|A|)
break@@@[Boolean(true)]
}
else -> {
}
}
break@@@[Boolean(true)]
}
R|<local>/x|.<Unresolved name: foo>#()
}
public final fun test_5(x: R|kotlin/Any|, b: R|kotlin/Boolean|): R|kotlin/Unit| {
do {
when () {
R|<local>/b| -> {
(R|<local>/x| as R|A|)
break@@@[Boolean(true)]
}
else -> {
}
}
}
while(Boolean(true))
R|<local>/x|.R|/A.foo|()
}
public final fun test_6(x: R|kotlin/Any|, b: R|kotlin/Boolean|): R|kotlin/Unit| {
do {
(R|<local>/x| as R|A|)
when () {
R|<local>/b| -> {
break@@@[Boolean(true)]
}
else -> {
}
}
}
while(Boolean(true))
R|<local>/x|.R|/A.foo|()
}
public final fun test_7(x: R|kotlin/Any|): R|kotlin/Unit| {
do {
(R|<local>/x| as R|A|)
}
while(Boolean(true))
R|<local>/x|.<Unresolved name: foo>#()
}
@@ -119,6 +119,11 @@ public class FirCfgBuildingTestGenerated extends AbstractFirCfgBuildingTest {
runTest("compiler/fir/resolve/testData/resolve/smartcasts/elvis.kt");
}
@TestMetadata("endlessLoops.kt")
public void testEndlessLoops() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/smartcasts/endlessLoops.kt");
}
@TestMetadata("equalsAndIdentity.kt")
public void testEqualsAndIdentity() throws Exception {
runTest("compiler/fir/resolve/testData/resolve/smartcasts/equalsAndIdentity.kt");