Control flow graph for safe calls corrected #KT-10913 Fixed
Also #KT-10186 Fixed Also #KT-5198 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
5ae394fec0
commit
a08b8f43b2
@@ -0,0 +1,160 @@
|
||||
== fn ==
|
||||
fun fn() : String? = null
|
||||
---------------------
|
||||
L0:
|
||||
1 <START>
|
||||
r(null) -> <v0>
|
||||
ret(*|<v0>) L1
|
||||
L1:
|
||||
<END> NEXT:[<SINK>]
|
||||
error:
|
||||
<ERROR> PREV:[]
|
||||
sink:
|
||||
<SINK> PREV:[<ERROR>, <END>]
|
||||
=====================
|
||||
== let ==
|
||||
inline fun <T, R> T.let(f: (T) -> R): R = f(this)
|
||||
---------------------
|
||||
L0:
|
||||
1 <START>
|
||||
v(f: (T) -> R)
|
||||
magic[FAKE_INITIALIZER](f: (T) -> R) -> <v0>
|
||||
w(f|<v0>)
|
||||
r(f) -> <v1>
|
||||
r(this, <this>) -> <v2>
|
||||
mark(f(this))
|
||||
call(f(this), invoke|<v1>, <v2>) -> <v3>
|
||||
ret(*|<v3>) L1
|
||||
L1:
|
||||
<END> NEXT:[<SINK>]
|
||||
error:
|
||||
<ERROR> PREV:[]
|
||||
sink:
|
||||
<SINK> PREV:[<ERROR>, <END>]
|
||||
=====================
|
||||
== foo ==
|
||||
fun foo(): String {
|
||||
val x = fn()?.let { throw Exception() } ?: "unreachable?"
|
||||
return x
|
||||
}
|
||||
---------------------
|
||||
L0:
|
||||
1 <START>
|
||||
2 mark({ val x = fn()?.let { throw Exception() } ?: "unreachable?" return x })
|
||||
v(val x = fn()?.let { throw Exception() } ?: "unreachable?")
|
||||
mark(fn()?.let { throw Exception() })
|
||||
jf(L2) NEXT:[mark(fn()?.let { throw Exception() } ?: "unreachable?"), mark(fn())]
|
||||
mark(fn())
|
||||
call(fn(), fn) -> <v0>
|
||||
mark({ throw Exception() })
|
||||
jmp?(L3) NEXT:[r({ throw Exception() }) -> <v1>, d({ throw Exception() })]
|
||||
d({ throw Exception() }) NEXT:[<SINK>]
|
||||
L3 [after local declaration]:
|
||||
r({ throw Exception() }) -> <v1> PREV:[jmp?(L3)]
|
||||
mark(let { throw Exception() })
|
||||
call(let { throw Exception() }, let|<v0>, <v1>)
|
||||
jmp(error) NEXT:[<ERROR>]
|
||||
L2 [result of call]:
|
||||
mark(fn()?.let { throw Exception() } ?: "unreachable?") PREV:[jf(L2)]
|
||||
jt(L6|!<v2>) NEXT:[mark("unreachable?"), merge(fn()?.let { throw Exception() } ?: "unreachable?"|!<v2>, <v3>) -> <v4>]
|
||||
mark("unreachable?")
|
||||
r("unreachable?") -> <v3>
|
||||
L6 [after elvis operator]:
|
||||
merge(fn()?.let { throw Exception() } ?: "unreachable?"|!<v2>, <v3>) -> <v4> PREV:[jt(L6|!<v2>), r("unreachable?") -> <v3>]
|
||||
w(x|<v4>)
|
||||
r(x) -> <v5>
|
||||
ret(*|<v5>) L1
|
||||
L1:
|
||||
1 <END> NEXT:[<SINK>]
|
||||
error:
|
||||
<ERROR> PREV:[jmp(error)]
|
||||
sink:
|
||||
<SINK> PREV:[<ERROR>, <END>, d({ throw Exception() })]
|
||||
=====================
|
||||
== anonymous_0 ==
|
||||
{ throw Exception() }
|
||||
---------------------
|
||||
L4:
|
||||
3 <START>
|
||||
4 mark(throw Exception())
|
||||
mark(throw Exception())
|
||||
mark(Exception())
|
||||
call(Exception(), <init>) -> <v0>
|
||||
throw (throw Exception()|<v0>) NEXT:[<ERROR>]
|
||||
- 3 ret(*|!<v1>) L5 PREV:[]
|
||||
L5:
|
||||
<END> NEXT:[<SINK>] PREV:[]
|
||||
error:
|
||||
<ERROR> PREV:[throw (throw Exception()|<v0>)]
|
||||
sink:
|
||||
<SINK> PREV:[<ERROR>, <END>]
|
||||
=====================
|
||||
== bar ==
|
||||
fun bar(): String {
|
||||
val x = fn() ?: return ""
|
||||
val y = x?.let { throw Exception() } ?: "unreachable"
|
||||
return y
|
||||
}
|
||||
---------------------
|
||||
L0:
|
||||
1 <START>
|
||||
2 mark({ val x = fn() ?: return "" val y = x?.let { throw Exception() } ?: "unreachable" return y })
|
||||
v(val x = fn() ?: return "")
|
||||
mark(fn())
|
||||
call(fn(), fn) -> <v0>
|
||||
mark(fn() ?: return "")
|
||||
jt(L2|<v0>) NEXT:[mark(""), merge(fn() ?: return ""|<v0>, !<v2>) -> <v3>]
|
||||
mark("")
|
||||
r("") -> <v1>
|
||||
ret(*|<v1>) L1 NEXT:[<END>]
|
||||
L2 [after elvis operator]:
|
||||
merge(fn() ?: return ""|<v0>, !<v2>) -> <v3> PREV:[jt(L2|<v0>)]
|
||||
w(x|<v3>)
|
||||
v(val y = x?.let { throw Exception() } ?: "unreachable")
|
||||
mark(x?.let { throw Exception() })
|
||||
jf(L3) NEXT:[jmp(error), r(x) -> <v4>]
|
||||
r(x) -> <v4>
|
||||
mark({ throw Exception() })
|
||||
jmp?(L4) NEXT:[r({ throw Exception() }) -> <v5>, d({ throw Exception() })]
|
||||
d({ throw Exception() }) NEXT:[<SINK>]
|
||||
L4 [after local declaration]:
|
||||
r({ throw Exception() }) -> <v5> PREV:[jmp?(L4)]
|
||||
mark(let { throw Exception() })
|
||||
call(let { throw Exception() }, let|<v4>, <v5>)
|
||||
jmp(error) NEXT:[<ERROR>]
|
||||
L3 [result of call]:
|
||||
jmp(error) NEXT:[<ERROR>] PREV:[jf(L3)]
|
||||
- mark(x?.let { throw Exception() } ?: "unreachable") PREV:[]
|
||||
- jt(L7|!<v6>) NEXT:[mark("unreachable"), merge(x?.let { throw Exception() } ?: "unreachable"|!<v6>, <v7>) -> <v8>] PREV:[]
|
||||
- mark("unreachable") PREV:[]
|
||||
- r("unreachable") -> <v7> PREV:[]
|
||||
L7 [after elvis operator]:
|
||||
- merge(x?.let { throw Exception() } ?: "unreachable"|!<v6>, <v7>) -> <v8> PREV:[]
|
||||
- w(y|<v8>) PREV:[]
|
||||
- r(y) -> <v9> PREV:[]
|
||||
- ret(*|<v9>) L1 PREV:[]
|
||||
L1:
|
||||
1 <END> NEXT:[<SINK>] PREV:[ret(*|<v1>) L1]
|
||||
error:
|
||||
<ERROR> PREV:[jmp(error), jmp(error)]
|
||||
sink:
|
||||
<SINK> PREV:[<ERROR>, <END>, d({ throw Exception() })]
|
||||
=====================
|
||||
== anonymous_1 ==
|
||||
{ throw Exception() }
|
||||
---------------------
|
||||
L5:
|
||||
3 <START>
|
||||
4 mark(throw Exception())
|
||||
mark(throw Exception())
|
||||
mark(Exception())
|
||||
call(Exception(), <init>) -> <v0>
|
||||
throw (throw Exception()|<v0>) NEXT:[<ERROR>]
|
||||
- 3 ret(*|!<v1>) L6 PREV:[]
|
||||
L6:
|
||||
<END> NEXT:[<SINK>] PREV:[]
|
||||
error:
|
||||
<ERROR> PREV:[throw (throw Exception()|<v0>)]
|
||||
sink:
|
||||
<SINK> PREV:[<ERROR>, <END>]
|
||||
=====================
|
||||
Reference in New Issue
Block a user