FIR checker: report tailrec problems on the keyword

FE1.0 reports it on the declaration signature. This is not ideal so we
move it to the `tailrec` keyword in FIR.
This commit is contained in:
Tianyu Geng
2021-09-23 20:34:27 -07:00
committed by teamcityserver
parent 922ae607f6
commit 5252effb10
26 changed files with 86 additions and 74 deletions
+10 -10
View File
@@ -2,17 +2,17 @@
// WITH_STDLIB
// !DIAGNOSTICS: -UNREACHABLE_CODE
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo1()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo1() {
<!NON_TAIL_RECURSIVE_CALL!>foo1<!>()
1
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo2()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo2() {
<!NON_TAIL_RECURSIVE_CALL!>foo2<!>()
val i = 1
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo3()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo3() {
<!NON_TAIL_RECURSIVE_CALL!>foo3<!>()
foo1()
}
@@ -27,7 +27,7 @@ tailrec fun foo5() {
foo4()
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo6(b: Boolean)<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo6(b: Boolean) {
while (b) {
<!NON_TAIL_RECURSIVE_CALL!>foo6<!>(!b)
}
@@ -40,21 +40,21 @@ tailrec fun foo7_return() {
}
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo7_break()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo7_break() {
while (true) {
<!NON_TAIL_RECURSIVE_CALL!>foo7_break<!>()
break
}
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo7_continue()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo7_continue() {
while (true) {
<!NON_TAIL_RECURSIVE_CALL!>foo7_continue<!>()
continue
}
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo8()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo8() {
while (true) {
<!NON_TAIL_RECURSIVE_CALL!>foo8<!>()
throw Exception()
@@ -62,19 +62,19 @@ tailrec fun foo7_return() {
foo8()
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo9()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo9() {
<!NON_TAIL_RECURSIVE_CALL!>foo9<!>()
fun bar() {}
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo10()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo10() {
<!NON_TAIL_RECURSIVE_CALL!>foo10<!>()
class Bar {
val i = 1
}
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo11(): String<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo11(): String {
return "hello ${<!NON_TAIL_RECURSIVE_CALL!>foo11<!>()}"
}
@@ -1,6 +1,6 @@
// WITH_STDLIB
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo1()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo1() {
run {
<!NON_TAIL_RECURSIVE_CALL!>foo1<!>()
}
@@ -9,13 +9,13 @@
fun myRun(f: () -> Unit) = f()
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo2()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo2() {
myRun {
<!NON_TAIL_RECURSIVE_CALL!>foo2<!>()
}
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo3()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo3() {
fun bar() {
<!NON_TAIL_RECURSIVE_CALL!>foo3<!>()
}
@@ -23,14 +23,14 @@ fun myRun(f: () -> Unit) = f()
}
class A {
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo4()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo4() {
with(this) {
<!NON_TAIL_RECURSIVE_CALL!>foo4<!>()
}
}
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo5()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo5() {
run {
return <!NON_TAIL_RECURSIVE_CALL!>foo5<!>()
}
+4 -4
View File
@@ -1,5 +1,5 @@
// FIR_IDENTICAL
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo1()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo1() {
try {
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo1<!>()
} catch (e: Exception) {
@@ -9,7 +9,7 @@
}
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo2()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo2() {
try {
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo2<!>()
foo1()
@@ -22,7 +22,7 @@
}
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo3()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo3() {
try {
try {
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo3<!>()
@@ -41,7 +41,7 @@
}
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo4()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo4() {
try {
if (true) {
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo4<!>()
@@ -1,15 +1,15 @@
//!LANGUAGE: -ProhibitTailrecOnVirtualMember
open class A {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec open fun foo(x: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun foo(x: Int) {
foo(x)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>internal tailrec open fun bar(y: Int)<!> {
internal <!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun bar(y: Int) {
bar(y)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>protected tailrec open fun baz(y: Int)<!> {
protected <!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun baz(y: Int) {
baz(y)
}
@@ -38,15 +38,15 @@ open class B : A() {
open class C : A() {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun foo(x: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> override fun foo(x: Int) {
foo(x)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun bar(y: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> override fun bar(y: Int) {
bar(y)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun baz(y: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> override fun baz(y: Int) {
baz(y)
}
}
@@ -66,15 +66,15 @@ object D : A() {
}
sealed class E : A() {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun foo(x: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> override fun foo(x: Int) {
foo(x)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun bar(y: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> override fun bar(y: Int) {
bar(y)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun baz(y: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> override fun baz(y: Int) {
baz(y)
}
@@ -109,15 +109,15 @@ enum class F {
}
};
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec open fun foo(x: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun foo(x: Int) {
foo(x)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>internal tailrec open fun bar(y: Int)<!> {
internal <!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun bar(y: Int) {
bar(y)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>protected tailrec open fun baz(y: Int)<!> {
protected <!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun baz(y: Int) {
baz(y)
}
@@ -134,15 +134,15 @@ enum class G {
G1;
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec open fun foo(x: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun foo(x: Int) {
foo(x)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>internal tailrec open fun bar(y: Int)<!> {
internal <!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun bar(y: Int) {
bar(y)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>protected tailrec open fun baz(y: Int)<!> {
protected <!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun baz(y: Int) {
baz(y)
}
@@ -168,4 +168,4 @@ val z = object : A() {
tailrec override fun baz(y: Int) {
baz(y)
}
}
}
@@ -2,15 +2,15 @@
//!LANGUAGE: +ProhibitTailrecOnVirtualMember
open class A {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec open fun foo(x: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun foo(x: Int) {
foo(x)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>internal tailrec open fun bar(y: Int)<!> {
internal <!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun bar(y: Int) {
bar(y)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>protected tailrec open fun baz(y: Int)<!> {
protected <!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun baz(y: Int) {
baz(y)
}
@@ -39,15 +39,15 @@ open class B : A() {
open class C : A() {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun foo(x: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> override fun foo(x: Int) {
foo(x)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun bar(y: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> override fun bar(y: Int) {
bar(y)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun baz(y: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> override fun baz(y: Int) {
baz(y)
}
}
@@ -67,15 +67,15 @@ object D : A() {
}
sealed class E : A() {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun foo(x: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> override fun foo(x: Int) {
foo(x)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun bar(y: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> override fun bar(y: Int) {
bar(y)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun baz(y: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> override fun baz(y: Int) {
baz(y)
}
@@ -110,15 +110,15 @@ enum class F {
}
};
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec open fun foo(x: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun foo(x: Int) {
foo(x)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>internal tailrec open fun bar(y: Int)<!> {
internal <!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun bar(y: Int) {
bar(y)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>protected tailrec open fun baz(y: Int)<!> {
protected <!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun baz(y: Int) {
baz(y)
}
@@ -135,15 +135,15 @@ enum class G {
G1;
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec open fun foo(x: Int)<!> {
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun foo(x: Int) {
foo(x)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>internal tailrec open fun bar(y: Int)<!> {
internal <!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun bar(y: Int) {
bar(y)
}
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>protected tailrec open fun baz(y: Int)<!> {
protected <!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec<!> open fun baz(y: Int) {
baz(y)
}
@@ -168,4 +168,4 @@ val z = object : A() {
tailrec override fun baz(y: Int) {
baz(y)
}
}
}
@@ -6,11 +6,11 @@ open class A {
}
class B: A() {
<!NO_TAIL_CALLS_FOUND!>tailrec override fun foo(x: Int)<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> override fun foo(x: Int) {
<!NON_TAIL_RECURSIVE_CALL!>foo<!>()
}
<!NO_TAIL_CALLS_FOUND!>tailrec override fun gav(y: Int, z: Int)<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> override fun gav(y: Int, z: Int) {
<!NON_TAIL_RECURSIVE_CALL!>gav<!>(y)
}
@@ -44,7 +44,7 @@ enum class E {
}
},
C {
<!NO_TAIL_CALLS_FOUND!>override tailrec fun rec()<!> {
override <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun rec() {
C.rec() // resolution goes to `E.rec`. Hence the resolved symbol is considered different from `C.rec`.
}
};
@@ -1,6 +1,6 @@
// FIR_IDENTICAL
class A(val a: A) {
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo1()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo1() {
a.<!NON_TAIL_RECURSIVE_CALL!>foo1<!>()
}
@@ -12,7 +12,7 @@ class A(val a: A) {
foo3()
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo4()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo4() {
with(a) {
<!NON_TAIL_RECURSIVE_CALL!>foo4<!>()
return
@@ -7,7 +7,7 @@ tailrec fun String.foo2() {
this.foo2()
}
<!NO_TAIL_CALLS_FOUND!>tailrec fun String.foo3()<!> {
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun String.foo3() {
with(this) {
<!NON_TAIL_RECURSIVE_CALL!>foo3<!>()
}
@@ -5,7 +5,7 @@ object O {
}
class A {
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo(i: Int)<!> = if (i < 0) 0 else A.foo(i - 1)
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo(i: Int) = if (i < 0) 0 else A.foo(i - 1)
companion object {
fun foo(i: Int) = 42 + i
@@ -13,5 +13,5 @@ class A {
}
class B {
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo(i: Int)<!> = if (i < 0) 0 else O.foo(i - 1)
}
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo(i: Int) = if (i < 0) 0 else O.foo(i - 1)
}