FIR CFG: ignore exception edges when looking for return values
^KT-54668 Fixed
This commit is contained in:
Vendored
+1
-1
@@ -15,5 +15,5 @@ FILE: lazyValWithElvisToNothingInside.kt
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
public get(): R|kotlin/collections/Map<kotlin/String, kotlin/String>| {
|
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|)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -7,8 +7,8 @@ interface A {
|
|||||||
|
|
||||||
fun getA(): A? = null
|
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 {
|
(getA() ?: error("error")).list.associateBy {
|
||||||
it
|
it
|
||||||
}
|
}
|
||||||
}<!>
|
}
|
||||||
|
|||||||
+2
-2
@@ -38,12 +38,12 @@ FILE: kotlinSam.kt
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
R|/foo1|(R|<local>/f|)
|
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)))
|
^ CMP(>, R|<local>/x|.<Unresolved name: compareTo>#(Int(1)))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
<Inapplicable(INAPPLICABLE): /foo2>#(R|<local>/f|)
|
<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)))
|
^ CMP(>, R|<local>/x|.<Unresolved name: compareTo>#(Int(1)))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
Vendored
+1
-1
@@ -2,7 +2,7 @@ FILE: main.kt
|
|||||||
public final fun foo(m: R|MyRunnable|): R|kotlin/Unit| {
|
public final fun foo(m: R|MyRunnable|): R|kotlin/Unit| {
|
||||||
}
|
}
|
||||||
public final fun main(): 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)))
|
^ CMP(>, R|<local>/x|.<Unresolved name: compareTo>#(Int(1)))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
+11
-6
@@ -97,24 +97,29 @@ class ControlFlowGraphBuilder {
|
|||||||
// ----------------------------------- Public API -----------------------------------
|
// ----------------------------------- Public API -----------------------------------
|
||||||
|
|
||||||
fun returnExpressionsOfAnonymousFunction(function: FirAnonymousFunction): Collection<FirStatement>? {
|
fun returnExpressionsOfAnonymousFunction(function: FirAnonymousFunction): Collection<FirStatement>? {
|
||||||
val exitNode = function.controlFlowGraphReference?.controlFlowGraph?.exitNode
|
val exitNode = function.controlFlowGraphReference?.controlFlowGraph?.exitNode ?: return null
|
||||||
?: return null
|
|
||||||
|
|
||||||
fun FirElement.extractArgument(): FirElement = when {
|
fun FirElement.extractArgument(): FirElement = when {
|
||||||
this is FirReturnExpression && target.labeledElement.symbol == function.symbol -> result.extractArgument()
|
this is FirReturnExpression && target.labeledElement.symbol == function.symbol -> result.extractArgument()
|
||||||
else -> this
|
else -> this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun CFGNode<*>.extractArgument(): FirElement? = when (this) {
|
fun CFGNode<*>.extractArgument(): FirStatement? = when (this) {
|
||||||
is FunctionEnterNode, is TryMainBlockEnterNode, is FinallyBlockExitNode, is CatchClauseEnterNode -> null
|
is FunctionEnterNode, is TryMainBlockEnterNode, is FinallyBlockExitNode, is CatchClauseEnterNode -> null
|
||||||
is BlockExitNode -> if (function.isLambda || isDead) firstPreviousNode.extractArgument() else null
|
is BlockExitNode -> if (function.isLambda || isDead) firstPreviousNode.extractArgument() else null
|
||||||
is StubNode -> firstPreviousNode.extractArgument()
|
is StubNode -> firstPreviousNode.extractArgument()
|
||||||
else -> fir.extractArgument()
|
else -> fir.extractArgument() as FirStatement?
|
||||||
}
|
}
|
||||||
|
|
||||||
return (nonDirectJumps[exitNode] + exitNode.previousNodes).mapNotNullTo(mutableSetOf()) {
|
val returnValues = exitNode.previousNodes.mapNotNullTo(mutableSetOf()) {
|
||||||
it.extractArgument() as FirStatement?
|
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)
|
@OptIn(CfgBuilderInternals::class)
|
||||||
|
|||||||
Reference in New Issue
Block a user