[FIR] Add DFA implications when one side of an Elvis operator is null

When one side of an Elvis operator can only be `null`, and the entire
Elvis operator expression cannot be `null`, this implies that the
opposite side of the Elvis operator cannot be `null`. Add such
implications to the Elvis exit node of the DFA. This helps smart-casting
of variables used within long Elvis operator chains.

#KT-49249 Fixed
This commit is contained in:
Brian Norman
2023-06-15 14:16:15 -05:00
committed by Space Team
parent 110cc79ddd
commit 8ac59592ed
3 changed files with 59 additions and 5 deletions
@@ -18,3 +18,22 @@ FILE: longElvisChain.kt
) } ?: ^test_2 Unit
throw R|<local>/a|
}
public final fun test_3(): R|kotlin/Unit| {
lval a: R|kotlin/Throwable?| = Null(null)
lval b: R|kotlin/Unit?| = Null(null)
lval c: R|kotlin/Throwable| = R|<local>/b|?.{ $subj$.R|kotlin/let|<R|kotlin/Unit|, R|kotlin/Nothing|>(<L> = let@fun <anonymous>(it: R|kotlin/Unit|): R|kotlin/Nothing| <inline=Inline, kind=EXACTLY_ONCE> {
^test_3 R|<local>/it|
}
) } ?: R|<local>/a| ?: ^test_3 Unit
R|<local>/c|!!
throw R|<local>/a|
}
public final fun test_4(): R|kotlin/Unit| {
lval a: R|kotlin/Throwable?| = Null(null)
lval b: R|kotlin/Unit?| = Null(null)
lval c: R|kotlin/Throwable| = R|<local>/b|?.{ $subj$.R|kotlin/let|<R|kotlin/Unit|, R|kotlin/Nothing|>(<L> = let@fun <anonymous>(it: R|kotlin/Unit|): R|kotlin/Nothing| <inline=Inline, kind=EXACTLY_ONCE> {
^test_4 R|<local>/it|
}
) } ?: R|<local>/a| ?: ^test_4 Unit
throw R|<local>/a|
}
@@ -6,12 +6,27 @@ fun test_1() {
val b: Unit? = null
val c = a ?: b?.let { return it } ?: return
c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
throw <!TYPE_MISMATCH!>a<!>
throw a
}
fun test_2() {
val a: Throwable? = null;
val b: Unit? = null
val c = a ?: b?.let { return it } ?: return
throw <!TYPE_MISMATCH!>a<!>
throw a
}
fun test_3() {
val a: Throwable? = null;
val b: Unit? = null
val c = b?.let { return it } ?: a ?: return
c<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
throw a
}
fun test_4() {
val a: Throwable? = null;
val b: Unit? = null
val c = b?.let { return it } ?: a ?: return
throw a
}