[FE 1.0] Always create return value for CallInstruction

This fixes missing `USED_AS_EXPRESSION` recordings
^KT-47527 Fixed
This commit is contained in:
Dmitriy Novozhilov
2021-06-30 16:40:55 +03:00
committed by TeamCityServer
parent b2372ff0b9
commit ae608ea67f
50 changed files with 496 additions and 204 deletions
@@ -103,13 +103,13 @@ L2 [after local declaration]:
mark({ return })
r({ return }) -> <v1>
mark(let { return })
call(let { return }, let|<v0>, <v1>)
call(let { return }, let|<v0>, <v1>) -> <v2>
L6 [before inlined declaration]:
inlined({ return }) NEXT:[<SINK>]
L5 [result of call]:
L7 [after inlined declaration]:
mark(f(null?.let { return })) PREV:[jf(L5)]
call(f(null?.let { return }), f|!<v2>) -> <v3>
call(f(null?.let { return }), f|<v2>) -> <v3>
mark(doSomething())
call(doSomething(), doSomething) -> <v4>
L1:
@@ -163,28 +163,28 @@ L0:
magic[FAKE_INITIALIZER](x: Any?) -> <v0>
w(x|<v0>)
mark(x?.let { return true })
jf(L2) NEXT:[mark(x?.let { return true } ?: false), r(x) -> <v1>]
jf(L2) NEXT:[mark(x?.let { return true } ?: false), r(x) -> <v1>]
r(x) -> <v1>
mark({ return true })
r({ return true }) -> <v2>
mark(let { return true })
call(let { return true }, let|<v1>, <v2>)
call(let { return true }, let|<v1>, <v2>) -> <v3>
L3 [before inlined declaration]:
inlined({ return true }) NEXT:[<SINK>]
inlined({ return true }) NEXT:[<SINK>]
L2 [result of call]:
L4 [after inlined declaration]:
mark(x?.let { return true } ?: false) PREV:[jf(L2)]
jt(L7|!<v3>) NEXT:[r(false) -> <v4>, merge(x?.let { return true } ?: false|!<v3>, <v4>) -> <v5>]
mark(x?.let { return true } ?: false) PREV:[jf(L2)]
jt(L7|<v3>) NEXT:[r(false) -> <v4>, merge(x?.let { return true } ?: false|<v3>, <v4>) -> <v5>]
r(false) -> <v4>
L7 [after elvis operator]:
merge(x?.let { return true } ?: false|!<v3>, <v4>) -> <v5> PREV:[jt(L7|!<v3>), r(false) -> <v4>]
merge(x?.let { return true } ?: false|<v3>, <v4>) -> <v5> PREV:[jt(L7|<v3>), r(false) -> <v4>]
ret(*|<v5>) L1
L1:
<END> NEXT:[<SINK>] PREV:[ret(*|<v0>) L1, ret(*|<v5>) L1]
<END> NEXT:[<SINK>] PREV:[ret(*|<v0>) L1, ret(*|<v5>) L1]
error:
<ERROR> PREV:[]
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>, inlined({ return true })]
<SINK> PREV:[<ERROR>, <END>, inlined({ return true })]
=====================
== inlined anonymous_2 ==
{
+6 -6
View File
@@ -45,9 +45,9 @@ fun test2() {
---------------------
null <v0>: Nothing NEW: r(null) -> <v0>
{ return } <v1>: {<: (Nothing) -> Nothing} NEW: r({ return }) -> <v1>
let { return } !<v2>: *
null?.let { return } !<v2>: * COPY
f(null?.let { return }) <v3>: * NEW: call(f(null?.let { return }), f|!<v2>) -> <v3>
let { return } <v2>: * NEW: call(let { return }, let|<v0>, <v1>) -> <v2>
null?.let { return } <v2>: * COPY
f(null?.let { return }) <v3>: * NEW: call(f(null?.let { return }), f|<v2>) -> <v3>
doSomething() <v4>: * NEW: call(doSomething(), doSomething) -> <v4>
{ fun f(x: Any?) = x f(null?.let { return }) // false unreachable here doSomething() } <v4>: * COPY
=====================
@@ -72,10 +72,10 @@ fun test3(x: Any?): Boolean =
<v0>: * NEW: magic[FAKE_INITIALIZER](x: Any?) -> <v0>
x <v1>: {<: Any} NEW: r(x) -> <v1>
{ return true } <v2>: {<: (Any) -> Nothing} NEW: r({ return true }) -> <v2>
let { return true } !<v3>: *
x?.let { return true } !<v3>: * COPY
let { return true } <v3>: Boolean NEW: call(let { return true }, let|<v1>, <v2>) -> <v3>
x?.let { return true } <v3>: Boolean COPY
false <v4>: Boolean NEW: r(false) -> <v4>
x?.let { return true } ?: false <v5>: Boolean NEW: merge(x?.let { return true } ?: false|!<v3>, <v4>) -> <v5>
x?.let { return true } ?: false <v5>: Boolean NEW: merge(x?.let { return true } ?: false|<v3>, <v4>) -> <v5>
=====================
== inlined anonymous_2 ==
{
@@ -106,10 +106,10 @@ L2 [after local declaration]:
L6 [after local declaration]:
r({ return }) -> <v1> PREV:[jmp?(L6)]
mark(let { return })
call(let { return }, let|<v0>, <v1>)
call(let { return }, let|<v0>, <v1>) -> <v2>
L5 [result of call]:
mark(f(null?.let { return })) PREV:[jf(L5), call(let { return }, let|<v0>, <v1>)]
call(f(null?.let { return }), f|!<v2>) -> <v3>
mark(f(null?.let { return })) PREV:[jf(L5), call(let { return }, let|<v0>, <v1>) -> <v2>]
call(f(null?.let { return }), f|<v2>) -> <v3>
mark(doSomething())
call(doSomething(), doSomething) -> <v4>
L1:
@@ -163,28 +163,28 @@ L0:
magic[FAKE_INITIALIZER](x: Any?) -> <v0>
w(x|<v0>)
mark(x?.let { return true })
jf(L2) NEXT:[mark(x?.let { return true } ?: false), r(x) -> <v1>]
jf(L2) NEXT:[mark(x?.let { return true } ?: false), r(x) -> <v1>]
r(x) -> <v1>
mark({ return true })
jmp?(L3) NEXT:[r({ return true }) -> <v2>, d({ return true })]
d({ return true }) NEXT:[<SINK>]
jmp?(L3) NEXT:[r({ return true }) -> <v2>, d({ return true })]
d({ return true }) NEXT:[<SINK>]
L3 [after local declaration]:
r({ return true }) -> <v2> PREV:[jmp?(L3)]
r({ return true }) -> <v2> PREV:[jmp?(L3)]
mark(let { return true })
call(let { return true }, let|<v1>, <v2>)
call(let { return true }, let|<v1>, <v2>) -> <v3>
L2 [result of call]:
mark(x?.let { return true } ?: false) PREV:[jf(L2), call(let { return true }, let|<v1>, <v2>)]
jt(L6|!<v3>) NEXT:[r(false) -> <v4>, merge(x?.let { return true } ?: false|!<v3>, <v4>) -> <v5>]
mark(x?.let { return true } ?: false) PREV:[jf(L2), call(let { return true }, let|<v1>, <v2>) -> <v3>]
jt(L6|<v3>) NEXT:[r(false) -> <v4>, merge(x?.let { return true } ?: false|<v3>, <v4>) -> <v5>]
r(false) -> <v4>
L6 [after elvis operator]:
merge(x?.let { return true } ?: false|!<v3>, <v4>) -> <v5> PREV:[jt(L6|!<v3>), r(false) -> <v4>]
merge(x?.let { return true } ?: false|<v3>, <v4>) -> <v5> PREV:[jt(L6|<v3>), r(false) -> <v4>]
ret(*|<v5>) L1
L1:
<END> NEXT:[<SINK>] PREV:[ret(*|<v0>) L1, ret(*|<v5>) L1]
<END> NEXT:[<SINK>] PREV:[ret(*|<v0>) L1, ret(*|<v5>) L1]
error:
<ERROR> PREV:[]
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>, d({ return true })]
<SINK> PREV:[<ERROR>, <END>, d({ return true })]
=====================
== anonymous_2 ==
{
@@ -45,9 +45,9 @@ fun test2() {
---------------------
null <v0>: Nothing NEW: r(null) -> <v0>
{ return } <v1>: {<: (Nothing) -> Nothing} NEW: r({ return }) -> <v1>
let { return } !<v2>: *
null?.let { return } !<v2>: * COPY
f(null?.let { return }) <v3>: * NEW: call(f(null?.let { return }), f|!<v2>) -> <v3>
let { return } <v2>: * NEW: call(let { return }, let|<v0>, <v1>) -> <v2>
null?.let { return } <v2>: * COPY
f(null?.let { return }) <v3>: * NEW: call(f(null?.let { return }), f|<v2>) -> <v3>
doSomething() <v4>: * NEW: call(doSomething(), doSomething) -> <v4>
{ fun f(x: Any?) = x f(null?.let { return }) // false unreachable here doSomething() } <v4>: * COPY
=====================
@@ -72,10 +72,10 @@ fun test3(x: Any?): Boolean =
<v0>: * NEW: magic[FAKE_INITIALIZER](x: Any?) -> <v0>
x <v1>: {<: Any} NEW: r(x) -> <v1>
{ return true } <v2>: {<: (Any) -> Nothing} NEW: r({ return true }) -> <v2>
let { return true } !<v3>: *
x?.let { return true } !<v3>: * COPY
let { return true } <v3>: Boolean NEW: call(let { return true }, let|<v1>, <v2>) -> <v3>
x?.let { return true } <v3>: Boolean COPY
false <v4>: Boolean NEW: r(false) -> <v4>
x?.let { return true } ?: false <v5>: Boolean NEW: merge(x?.let { return true } ?: false|!<v3>, <v4>) -> <v5>
x?.let { return true } ?: false <v5>: Boolean NEW: merge(x?.let { return true } ?: false|<v3>, <v4>) -> <v5>
=====================
== anonymous_2 ==
{
+7 -7
View File
@@ -52,14 +52,14 @@ L0:
L3 [after local declaration]:
r({ throw Exception() }) -> <v1> PREV:[jmp?(L3)]
mark(let { throw Exception() })
call(let { throw Exception() }, let|<v0>, <v1>)
call(let { throw Exception() }, let|<v0>, <v1>) -> <v2>
L2 [result of call]:
mark(fn()?.let { throw Exception() } ?: "unreachable?") PREV:[jf(L2), call(let { throw Exception() }, let|<v0>, <v1>)]
jt(L6|!<v2>) NEXT:[mark("unreachable?"), merge(fn()?.let { throw Exception() } ?: "unreachable?"|!<v2>, <v3>) -> <v4>]
mark(fn()?.let { throw Exception() } ?: "unreachable?") PREV:[jf(L2), call(let { throw Exception() }, let|<v0>, <v1>) -> <v2>]
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>]
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
@@ -119,16 +119,16 @@ L2 [after elvis operator]:
L4 [after local declaration]:
r({ throw Exception() }) -> <v5> PREV:[jmp?(L4)]
mark(let { throw Exception() })
call(let { throw Exception() }, let|<v4>, <v5>)
call(let { throw Exception() }, let|<v4>, <v5>) -> <v6>
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:[]
- 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:[]
- merge(x?.let { throw Exception() } ?: "unreachable"|<v6>, <v7>) -> <v8> PREV:[]
- w(y|<v8>) PREV:[]
- r(y) -> <v9> PREV:[]
- ret(*|<v9>) L1 PREV:[]
+6 -6
View File
@@ -20,10 +20,10 @@ fun foo(): String {
---------------------
fn() <v0>: String NEW: call(fn(), fn) -> <v0>
{ throw Exception() } <v1>: {<: (String) -> Nothing} NEW: r({ throw Exception() }) -> <v1>
let { throw Exception() } !<v2>: *
fn()?.let { throw Exception() } !<v2>: * COPY
let { throw Exception() } <v2>: AND{Boolean, String} NEW: call(let { throw Exception() }, let|<v0>, <v1>) -> <v2>
fn()?.let { throw Exception() } <v2>: AND{Boolean, String} COPY
"unreachable?" <v3>: String NEW: r("unreachable?") -> <v3>
fn()?.let { throw Exception() } ?: "unreachable?" <v4>: String NEW: merge(fn()?.let { throw Exception() } ?: "unreachable?"|!<v2>, <v3>) -> <v4>
fn()?.let { throw Exception() } ?: "unreachable?" <v4>: String NEW: merge(fn()?.let { throw Exception() } ?: "unreachable?"|<v2>, <v3>) -> <v4>
x <v5>: String NEW: r(x) -> <v5>
return x !<v6>: *
{ val x = fn()?.let { throw Exception() } ?: "unreachable?" return x } !<v6>: * COPY
@@ -48,10 +48,10 @@ return ""
fn() ?: return "" <v3>: String NEW: merge(fn() ?: return ""|<v0>, !<v2>) -> <v3>
x <v4>: String NEW: r(x) -> <v4>
{ throw Exception() } <v5>: {<: (String) -> Nothing} NEW: r({ throw Exception() }) -> <v5>
let { throw Exception() } !<v6>: *
x?.let { throw Exception() } !<v6>: * COPY
let { throw Exception() } <v6>: AND{Boolean, String} NEW: call(let { throw Exception() }, let|<v4>, <v5>) -> <v6>
x?.let { throw Exception() } <v6>: AND{Boolean, String} COPY
"unreachable" <v7>: String NEW: r("unreachable") -> <v7>
x?.let { throw Exception() } ?: "unreachable" <v8>: String NEW: merge(x?.let { throw Exception() } ?: "unreachable"|!<v6>, <v7>) -> <v8>
x?.let { throw Exception() } ?: "unreachable" <v8>: String NEW: merge(x?.let { throw Exception() } ?: "unreachable"|<v6>, <v7>) -> <v8>
y <v9>: String NEW: r(y) -> <v9>
return y !<v10>: *
{ val x = fn() ?: return "" val y = x?.let { throw Exception() } ?: "unreachable" return y } !<v10>: * COPY