[FIR] Don't assume that exit lambda node is target for exceptional exit for inplace lambdas
#KT-39709 Fixed #KT-43156 Fixed
This commit is contained in:
committed by
teamcityserver
parent
440cf78884
commit
87380d1913
+1
-1
@@ -246,7 +246,7 @@ digraph propertiesAndInitBlocks_kt {
|
|||||||
28 -> {48 34} [color=green];
|
28 -> {48 34} [color=green];
|
||||||
28 -> {48 34} [style=dashed];
|
28 -> {48 34} [style=dashed];
|
||||||
29 -> {30};
|
29 -> {30};
|
||||||
30 -> {33};
|
30 -> {81};
|
||||||
30 -> {31} [style=dotted];
|
30 -> {31} [style=dotted];
|
||||||
31 -> {32} [style=dotted];
|
31 -> {32} [style=dotted];
|
||||||
32 -> {33} [style=dotted];
|
32 -> {33} [style=dotted];
|
||||||
|
|||||||
+9
-4
@@ -270,7 +270,9 @@ class ControlFlowGraphBuilder {
|
|||||||
val exitNode = createFunctionExitNode(anonymousFunction).also {
|
val exitNode = createFunctionExitNode(anonymousFunction).also {
|
||||||
exitsOfAnonymousFunctions[symbol] = it
|
exitsOfAnonymousFunctions[symbol] = it
|
||||||
exitTargetsForReturn.push(it)
|
exitTargetsForReturn.push(it)
|
||||||
exitTargetsForTry.push(it)
|
if (!invocationKind.isInPlace) {
|
||||||
|
exitTargetsForTry.push(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invocationKind.hasTowardEdge) {
|
if (invocationKind.hasTowardEdge) {
|
||||||
@@ -299,13 +301,16 @@ class ControlFlowGraphBuilder {
|
|||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val EventOccurrencesRange?.isInPlace: Boolean
|
||||||
|
get() = this != null
|
||||||
|
|
||||||
fun exitAnonymousFunction(anonymousFunction: FirAnonymousFunction): Triple<FunctionExitNode, PostponedLambdaExitNode?, ControlFlowGraph> {
|
fun exitAnonymousFunction(anonymousFunction: FirAnonymousFunction): Triple<FunctionExitNode, PostponedLambdaExitNode?, ControlFlowGraph> {
|
||||||
|
|
||||||
|
|
||||||
val symbol = anonymousFunction.symbol
|
val symbol = anonymousFunction.symbol
|
||||||
val exitNode = exitsOfAnonymousFunctions.remove(symbol)!!.also {
|
val exitNode = exitsOfAnonymousFunctions.remove(symbol)!!.also {
|
||||||
require(it == exitTargetsForReturn.pop())
|
require(it == exitTargetsForReturn.pop())
|
||||||
require(it == exitTargetsForTry.pop())
|
if (!anonymousFunction.invocationKind.isInPlace) {
|
||||||
|
require(it == exitTargetsForTry.pop())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
popAndAddEdge(exitNode)
|
popAndAddEdge(exitNode)
|
||||||
exitNode.updateDeadStatus()
|
exitNode.updateDeadStatus()
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
class A {
|
|
||||||
fun test() {
|
|
||||||
val a: A
|
|
||||||
synchronized(this) {
|
|
||||||
if (bar()) throw RuntimeException()
|
|
||||||
a = A()
|
|
||||||
}
|
|
||||||
<!UNINITIALIZED_VARIABLE!>a<!>.bar()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun bar() = false
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
class A {
|
class A {
|
||||||
fun test() {
|
fun test() {
|
||||||
val a: A
|
val a: A
|
||||||
|
|||||||
+2
-2
@@ -30,7 +30,7 @@ fun innerTryCatchInitializes() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Can get here only when inlined lambda exited properly, i.e. x is initialized
|
// Can get here only when inlined lambda exited properly, i.e. x is initialized
|
||||||
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
|
x.inc()
|
||||||
outerComputation()
|
outerComputation()
|
||||||
|
|
||||||
} catch (e: java.lang.Exception) {
|
} catch (e: java.lang.Exception) {
|
||||||
@@ -44,4 +44,4 @@ fun innerTryCatchInitializes() {
|
|||||||
}
|
}
|
||||||
// Here x=I because outer try-catch either exited normally (x=I) or catched exception (x=I, with reassingment, though)
|
// Here x=I because outer try-catch either exited normally (x=I) or catched exception (x=I, with reassingment, though)
|
||||||
x.inc()
|
x.inc()
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -26,7 +26,7 @@ fun throwIfNotCalled() {
|
|||||||
}
|
}
|
||||||
// x *is* initialized here, because if myRun was never called -> exception
|
// x *is* initialized here, because if myRun was never called -> exception
|
||||||
// were thrown and control flow wouldn't be here
|
// were thrown and control flow wouldn't be here
|
||||||
println(<!UNINITIALIZED_VARIABLE!>x<!>)
|
println(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun catchThrowIfNotCalled() {
|
fun catchThrowIfNotCalled() {
|
||||||
@@ -45,4 +45,4 @@ fun catchThrowIfNotCalled() {
|
|||||||
|
|
||||||
// x *isn't* initialized here!
|
// x *isn't* initialized here!
|
||||||
println(<!UNINITIALIZED_VARIABLE!>x<!>)
|
println(<!UNINITIALIZED_VARIABLE!>x<!>)
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -43,7 +43,7 @@ fun possibleReassignmentInTryCatch() {
|
|||||||
}
|
}
|
||||||
x.inc()
|
x.inc()
|
||||||
}
|
}
|
||||||
<!UNINITIALIZED_VARIABLE!>x<!>.inc()
|
x.inc()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tryCatchOuter() {
|
fun tryCatchOuter() {
|
||||||
|
|||||||
+1
-1
@@ -98,7 +98,7 @@ class DefiniteInitializationAfterThrow {
|
|||||||
if (bar()) throw RuntimeException()
|
if (bar()) throw RuntimeException()
|
||||||
a = 42
|
a = 42
|
||||||
}
|
}
|
||||||
<!UNINITIALIZED_VARIABLE!>a<!>.hashCode()
|
a.hashCode()
|
||||||
}
|
}
|
||||||
fun bar() = false
|
fun bar() = false
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -147,7 +147,7 @@ fun case_9() {
|
|||||||
}
|
}
|
||||||
throw Exception()
|
throw Exception()
|
||||||
}
|
}
|
||||||
println(<!UNINITIALIZED_VARIABLE!>x<!>.inc())
|
println(x.inc())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TESTCASE NUMBER: 10
|
// TESTCASE NUMBER: 10
|
||||||
|
|||||||
Reference in New Issue
Block a user