FIR CFG: ignore exception edges when looking for return values

^KT-54668 Fixed
This commit is contained in:
pyos
2022-11-28 11:14:07 +01:00
committed by teamcity
parent 664a70ec13
commit 9f4cfa2c50
5 changed files with 17 additions and 12 deletions
@@ -15,5 +15,5 @@ FILE: lazyValWithElvisToNothingInside.kt
}
)
public get(): R|kotlin/collections/Map<kotlin/String, kotlin/String>| {
^ D|/x|.<CS errors: kotlin/getValue>#<R|kotlin/collections/Map<kotlin/String, kotlin/String>|>(Null(null), ::R|/x|)
^ D|/x|.R|kotlin/getValue|<R|kotlin/collections/Map<kotlin/String, kotlin/String>|>(Null(null), ::R|/x|)
}
@@ -7,8 +7,8 @@ interface A {
fun getA(): A? = null
val x by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, NEW_INFERENCE_ERROR!>lazy {
val x by lazy {
(getA() ?: error("error")).list.associateBy {
it
}
}<!>
}
@@ -38,12 +38,12 @@ FILE: kotlinSam.kt
}
)
R|/foo1|(R|<local>/f|)
<Inapplicable(INAPPLICABLE): /foo2>#(<L> = foo2@fun <anonymous>(x: R|kotlin/Nothing|): R|kotlin/Nothing| <inline=Unknown> {
<Inapplicable(INAPPLICABLE): /foo2>#(<L> = foo2@fun <anonymous>(x: R|kotlin/Nothing|): R|kotlin/Boolean| <inline=Unknown> {
^ CMP(>, R|<local>/x|.<Unresolved name: compareTo>#(Int(1)))
}
)
<Inapplicable(INAPPLICABLE): /foo2>#(R|<local>/f|)
<Inapplicable(INAPPLICABLE): /foo3>#(<L> = foo3@fun <anonymous>(x: R|kotlin/Nothing|): R|kotlin/Nothing| <inline=Unknown> {
<Inapplicable(INAPPLICABLE): /foo3>#(<L> = foo3@fun <anonymous>(x: R|kotlin/Nothing|): R|kotlin/Boolean| <inline=Unknown> {
^ CMP(>, R|<local>/x|.<Unresolved name: compareTo>#(Int(1)))
}
)
@@ -2,7 +2,7 @@ FILE: main.kt
public final fun foo(m: R|MyRunnable|): R|kotlin/Unit| {
}
public final fun main(): R|kotlin/Unit| {
Q|JavaUsage|.<Inapplicable(INAPPLICABLE): /JavaUsage.foo>#(<L> = foo@fun <anonymous>(x: R|kotlin/Nothing|): R|kotlin/Nothing| <inline=Unknown> {
Q|JavaUsage|.<Inapplicable(INAPPLICABLE): /JavaUsage.foo>#(<L> = foo@fun <anonymous>(x: R|kotlin/Nothing|): R|kotlin/Boolean| <inline=Unknown> {
^ CMP(>, R|<local>/x|.<Unresolved name: compareTo>#(Int(1)))
}
)
@@ -97,24 +97,29 @@ class ControlFlowGraphBuilder {
// ----------------------------------- Public API -----------------------------------
fun returnExpressionsOfAnonymousFunction(function: FirAnonymousFunction): Collection<FirStatement>? {
val exitNode = function.controlFlowGraphReference?.controlFlowGraph?.exitNode
?: return null
val exitNode = function.controlFlowGraphReference?.controlFlowGraph?.exitNode ?: return null
fun FirElement.extractArgument(): FirElement = when {
this is FirReturnExpression && target.labeledElement.symbol == function.symbol -> result.extractArgument()
else -> this
}
fun CFGNode<*>.extractArgument(): FirElement? = when (this) {
fun CFGNode<*>.extractArgument(): FirStatement? = when (this) {
is FunctionEnterNode, is TryMainBlockEnterNode, is FinallyBlockExitNode, is CatchClauseEnterNode -> null
is BlockExitNode -> if (function.isLambda || isDead) firstPreviousNode.extractArgument() else null
is StubNode -> firstPreviousNode.extractArgument()
else -> fir.extractArgument()
else -> fir.extractArgument() as FirStatement?
}
return (nonDirectJumps[exitNode] + exitNode.previousNodes).mapNotNullTo(mutableSetOf()) {
it.extractArgument() as FirStatement?
val returnValues = exitNode.previousNodes.mapNotNullTo(mutableSetOf()) {
val edge = exitNode.incomingEdges.getValue(it)
// * NormalPath: last expression = return value
// * UncaughtExceptionPath: last expression = whatever threw, *not* a return value
// * ReturnPath(this lambda): these go from `finally` blocks, so that's not the return value;
// look in `nonDirectJumps` instead.
it.takeIf { edge.kind.usedInCfa && edge.label == NormalPath }?.extractArgument()
}
return nonDirectJumps[exitNode].mapNotNullTo(returnValues) { it.extractArgument() }
}
@OptIn(CfgBuilderInternals::class)