[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:
Dmitriy Novozhilov
2020-11-12 11:39:18 +03:00
committed by teamcityserver
parent 440cf78884
commit 87380d1913
9 changed files with 18 additions and 24 deletions
@@ -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];
@@ -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
@@ -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) {
@@ -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() {
@@ -43,7 +43,7 @@ fun possibleReassignmentInTryCatch() {
} }
x.inc() x.inc()
} }
<!UNINITIALIZED_VARIABLE!>x<!>.inc() x.inc()
} }
fun tryCatchOuter() { fun tryCatchOuter() {
@@ -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
} }
@@ -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