[FIR] Support PreliminaryLoopVisitor in FIR DFA

This commit is contained in:
Dmitriy Novozhilov
2021-02-11 17:42:30 +03:00
parent 0e46a961a3
commit 5711a8d610
34 changed files with 294 additions and 106 deletions
+1 -2
View File
@@ -1,6 +1,5 @@
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// IGNORE_BACKEND_FIR: JVM_IR
open class A {
fun Foo() {
@@ -23,4 +22,4 @@ fun box(): String {
test.Foo()
return "OK"
}
}
+43
View File
@@ -0,0 +1,43 @@
// ISSUE: KT-44804
// WITH_STDLIB
abstract class AbstractInsnNode(val next: AbstractInsnNode? = null)
class LineNumberNode(next: AbstractInsnNode? = null) : AbstractInsnNode(next) {
val line: Int = 1
}
class LabelNode() : AbstractInsnNode(null)
fun isDeadLineNumber(insn: LineNumberNode, index: Int, frames: Array<out Any?>): Boolean {
// Line number node is "dead" if the corresponding line number interval
// contains at least one "dead" meaningful instruction and no "live" meaningful instructions.
var finger: AbstractInsnNode = insn
var fingerIndex = index
var hasDeadInsn = false
loop@ while (true) {
finger = finger.next ?: break
fingerIndex++
when (finger) {
is LabelNode ->
continue@loop
is LineNumberNode ->
if (finger.line != insn.line) return hasDeadInsn
else -> {
if (frames[fingerIndex] != null) return false
hasDeadInsn = true
}
}
}
return true
}
fun box(): String {
val node = LineNumberNode(
LineNumberNode(
LabelNode()
)
)
val result = isDeadLineNumber(node, 0, arrayOf(null, null, "aaa", "bbb"))
return if (result) "OK" else "fail"
}
@@ -10,5 +10,5 @@ fun use() {
// Write to x is AFTER
x.hashCode()
// No smart cast should be here!
foo(bar { x = null }, x.hashCode())
foo(bar { x = null }, x<!UNSAFE_CALL!>.<!>hashCode())
}
@@ -4,10 +4,10 @@ fun foo(arg: Int?) {
if (x == null) return
run {
// Unsafe because of owner modification
x.hashCode()
x<!UNSAFE_CALL!>.<!>hashCode()
x = null
}
if (x != null) x = 42
// Unsafe because of lambda
x<!UNSAFE_CALL!>.<!>hashCode()
}
}
@@ -6,5 +6,5 @@ fun foo(x: Int, f: () -> Unit, y: Int) {}
fun bar() {
var x: Int?
x = 4
foo(x, { x = null; x<!UNSAFE_CALL!>.<!>hashCode() }, x)
<!INAPPLICABLE_CANDIDATE!>foo<!>(x, { x = null; x<!UNSAFE_CALL!>.<!>hashCode() }, x)
}
@@ -2,8 +2,8 @@ public fun foo() {
var i: Any = 1
if (i is Int) {
while (i != 10) {
i++ // Here smart cast should not be performed due to a successor
i<!UNRESOLVED_REFERENCE!>++<!> // Here smart cast should not be performed due to a successor
i = ""
}
}
}
}
@@ -2,7 +2,7 @@ public fun foo() {
var i: Any = 1
if (i is Int) {
while (i != 10) {
i++
i<!UNRESOLVED_REFERENCE!>++<!>
}
}
}
}
@@ -13,5 +13,5 @@ fun list(start: String) {
e = e.next()
}
// e can never be null but we do not know it
e.hashCode()
}
e<!UNSAFE_CALL!>.<!>hashCode()
}
@@ -13,7 +13,7 @@ fun foo(): Bar {
y = Bar()
while (x != null) {
// Here call is unsafe because of inner loop
y.next()
y<!UNSAFE_CALL!>.<!>next()
while (y != null) {
if (x == y)
// x is not null because of outer while
@@ -25,4 +25,4 @@ fun foo(): Bar {
x = x.next()
}
return Bar()
}
}
@@ -30,7 +30,7 @@ fun baz(s: String?) {
x.hashCode()
}
run {
x.hashCode()
x<!UNSAFE_CALL!>.<!>hashCode()
x = null
}
}
@@ -40,11 +40,11 @@ fun gaz(s: String?) {
var x = s
if (x != null) {
run {
x.hashCode()
x<!UNSAFE_CALL!>.<!>hashCode()
x = null
}
run {
x.hashCode()
x<!UNSAFE_CALL!>.<!>hashCode()
}
}
}
@@ -57,4 +57,4 @@ fun gav(s: String?) {
}
x = null
}
}
}
@@ -1,21 +0,0 @@
data class SomeObject(val n: SomeObject?) {
fun doSomething(): Boolean = true
fun next(): SomeObject? = n
}
fun list(start: SomeObject) {
var e: SomeObject?
e = start
do {
// In theory smart cast is possible here
// But in practice we have a loop with changing e
// ?: should we "or" entrance type info with condition type info?
if (!e.doSomething())
break
// Smart cast here is still not possible
e = e.next()
} while (e != null)
// e can be null because of next()
e.doSomething()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
data class SomeObject(val n: SomeObject?) {
fun doSomething(): Boolean = true
fun next(): SomeObject? = n
@@ -1,12 +0,0 @@
fun x(): Boolean { return true }
public fun foo(pp: String?): Int {
var p = pp
do {
p!!.length
if (p == "abc") break
p = null
} while (!x())
// Smart cast is NOT possible here
return p.length
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
fun x(): Boolean { return true }
public fun foo(pp: String?): Int {
@@ -9,9 +9,9 @@ fun list(start: SomeObject): SomeObject {
var e: SomeObject? = start
for (i in 0..42) {
// Unsafe calls because of nullable e at the beginning
e.doSomething()
e = e.next()
e<!UNSAFE_CALL!>.<!>doSomething()
e = e<!UNSAFE_CALL!>.<!>next()
}
// Smart cast is not possible here due to next()
return e
}
}
@@ -16,5 +16,5 @@ fun list(start: SomeObject) {
e = e.next()
}
// e can be null because of next()
e.doSomething()
}
e<!UNSAFE_CALL!>.<!>doSomething()
}
@@ -2,8 +2,8 @@ public fun foo() {
var i: Int? = 1
if (i != null) {
while (i != 10) {
i++ // Here smart cast should not be performed due to a successor
i<!UNSAFE_CALL!>++<!> // Here smart cast should not be performed due to a successor
i = null
}
}
}
}
@@ -2,7 +2,7 @@ public fun foo() {
var i: Int? = 1
if (i != null) {
while (i != 10) {
i++
i<!UNSAFE_CALL!>++<!>
}
}
}
}
@@ -13,5 +13,5 @@ fun list(start: SomeObject) {
e = e.next()
}
// e can be null because of next()
e.doSomething()
}
e<!UNSAFE_CALL!>.<!>doSomething()
}