提交 83e32016 编写于 作者: J Jinseong Jeon 提交者: Dmitriy Novozhilov

FIR DFA: correct exit node retrieval when a safe call is the last expression

^KT-44699 Fixed
上级 266432a4
FILE: safeCallOnTypeAlias.kt FILE: safeCallOnTypeAlias.kt
public final typealias MyTypeAlias = R|() -> kotlin/String?| public final typealias MyTypeAlias = R|() -> kotlin/String?|
public final fun foo(x: R|MyTypeAlias|): R|kotlin/Unit| { public final fun foo(x: R|MyTypeAlias|): R|kotlin/Unit| {
R|<local>/x|?.{ $subj$.R|kotlin/let|<R|() -> kotlin/String?|, R|kotlin/String|>(<L> = let@fun <anonymous>(y: R|() -> kotlin/String?|): R|kotlin/String| <kind=EXACTLY_ONCE> { R|<local>/x|?.{ $subj$.R|kotlin/let|<R|() -> kotlin/String?|, R|kotlin/String?|>(<L> = let@fun <anonymous>(y: R|() -> kotlin/String?|): R|kotlin/String?| <kind=EXACTLY_ONCE> {
^ R|<local>/y|.R|SubstitutionOverride<kotlin/Function0.invoke: R|kotlin/String?|>|()?.{ $subj$.R|kotlin/let|<R|kotlin/String|, R|kotlin/String|>(<L> = let@fun <anonymous>(result: R|kotlin/String|): R|kotlin/String| <kind=EXACTLY_ONCE> { ^ R|<local>/y|.R|SubstitutionOverride<kotlin/Function0.invoke: R|kotlin/String?|>|()?.{ $subj$.R|kotlin/let|<R|kotlin/String|, R|kotlin/String|>(<L> = let@fun <anonymous>(result: R|kotlin/String|): R|kotlin/String| <kind=EXACTLY_ONCE> {
^ R|/bar|(R|<local>/result|) ^ R|/bar|(R|<local>/result|)
} }
......
...@@ -11,7 +11,7 @@ FILE: coercionToUnitWithEarlyReturn.kt ...@@ -11,7 +11,7 @@ FILE: coercionToUnitWithEarlyReturn.kt
public final fun foo(x: R|() -> kotlin/Unit|): R|kotlin/Unit| { public final fun foo(x: R|() -> kotlin/Unit|): R|kotlin/Unit| {
} }
public final fun main(x: R|A?|): R|kotlin/Unit| { public final fun main(x: R|A?|): R|kotlin/Unit| {
lval lambda: R|() -> kotlin/Unit| = l@fun <anonymous>(): R|kotlin/Unit| { lval lambda: R|() -> kotlin/Unit?| = l@fun <anonymous>(): R|kotlin/Unit?| {
when () { when () {
==(R|<local>/x|?.{ $subj$.R|kotlin/Any.hashCode|() }, Int(0)) -> { ==(R|<local>/x|?.{ $subj$.R|kotlin/Any.hashCode|() }, Int(0)) -> {
^@l Unit ^@l Unit
...@@ -21,5 +21,5 @@ FILE: coercionToUnitWithEarlyReturn.kt ...@@ -21,5 +21,5 @@ FILE: coercionToUnitWithEarlyReturn.kt
^ R|<local>/x|?.{ $subj$.R|/A.unit|() } ^ R|<local>/x|?.{ $subj$.R|/A.unit|() }
} }
R|/foo|(R|<local>/lambda|) <Inapplicable(INAPPLICABLE): /foo>#(R|<local>/lambda|)
} }
...@@ -15,5 +15,5 @@ fun main(x: A?) { ...@@ -15,5 +15,5 @@ fun main(x: A?) {
} }
// lambda has a type (() -> Unit?) // lambda has a type (() -> Unit?)
foo(lambda) <!INAPPLICABLE_CANDIDATE{LT}!><!INAPPLICABLE_CANDIDATE{PSI}!>foo<!>(lambda)<!>
} }
...@@ -133,7 +133,6 @@ class ControlFlowGraphBuilder { ...@@ -133,7 +133,6 @@ class ControlFlowGraphBuilder {
fun CFGNode<*>.extractArgument(): FirElement? = when (this) { fun CFGNode<*>.extractArgument(): FirElement? = when (this) {
is FunctionEnterNode, is TryMainBlockEnterNode, is CatchClauseEnterNode -> null is FunctionEnterNode, is TryMainBlockEnterNode, is CatchClauseEnterNode -> null
is ExitSafeCallNode -> lastPreviousNode.extractArgument()
is StubNode, is BlockExitNode -> firstPreviousNode.extractArgument() is StubNode, is BlockExitNode -> firstPreviousNode.extractArgument()
else -> fir.extractArgument() else -> fir.extractArgument()
} }
...@@ -1090,8 +1089,9 @@ class ControlFlowGraphBuilder { ...@@ -1090,8 +1089,9 @@ class ControlFlowGraphBuilder {
* lastNode -> exitNode * lastNode -> exitNode
* instead of * instead of
* lastNode -> enterNode -> exitNode * lastNode -> enterNode -> exitNode
* because of we need to fork flow on `enterNode`, so `exitNode` * because we need to fork flow before `enterNode`, so `exitNode`
* will have unchanged flow from `lastNode` * will have unchanged flow from `lastNode`
* which corresponds to a path with nullable receiver.
*/ */
val lastNode = lastNodes.pop() val lastNode = lastNodes.pop()
val enterNode = createEnterSafeCallNode(safeCall) val enterNode = createEnterSafeCallNode(safeCall)
...@@ -1104,6 +1104,12 @@ class ControlFlowGraphBuilder { ...@@ -1104,6 +1104,12 @@ class ControlFlowGraphBuilder {
} }
fun exitSafeCall(): ExitSafeCallNode { fun exitSafeCall(): ExitSafeCallNode {
// There will be two paths towards this exit safe call node:
// one from the node prior to the enclosing safe call, and
// the other from the selector part in the enclosing safe call.
// Note that *neither* points to the safe call directly.
// So, when it comes to the real exit of the enclosing block/function,
// the safe call bound to this exit safe call node should be retrieved.
return exitSafeCallNodes.pop().also { return exitSafeCallNodes.pop().also {
addNewSimpleNode(it) addNewSimpleNode(it)
it.updateDeadStatus() it.updateDeadStatus()
......
// !WITH_NEW_INFERENCE
interface ClassId
interface JavaAnnotation {
val classId: ClassId?
}
interface JavaAnnotationOwner {
val annotations: Collection<JavaAnnotation>
}
interface MapBasedJavaAnnotationOwner : JavaAnnotationOwner {
val annotationsByFqNameHash: Map<Int?, JavaAnnotation>
}
fun JavaAnnotationOwner.buildLazyValueForMap() = lazy {
annotations.associateBy { it.classId?.hashCode() }
}
abstract class BinaryJavaMethodBase(): MapBasedJavaAnnotationOwner {
override val <!PROPERTY_TYPE_MISMATCH_ON_OVERRIDE!>annotationsByFqNameHash<!> by buildLazyValueForMap()
}
// FIR_IDENTICAL
interface ClassId interface ClassId
interface JavaAnnotation { interface JavaAnnotation {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册