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
@@ -821,8 +821,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
// TODO: replace with KtParameter // TODO: replace with KtParameter
val CANNOT_INFER_PARAMETER_TYPE by error<KtElement>() val CANNOT_INFER_PARAMETER_TYPE by error<KtElement>()
val NO_TAIL_CALLS_FOUND by warning<KtNamedFunction>(PositioningStrategy.DECLARATION_SIGNATURE) val NO_TAIL_CALLS_FOUND by warning<KtNamedFunction>(PositioningStrategy.TAILREC_MODIFIER)
val TAILREC_ON_VIRTUAL_MEMBER_ERROR by error<KtNamedFunction>(PositioningStrategy.DECLARATION_SIGNATURE) val TAILREC_ON_VIRTUAL_MEMBER_ERROR by error<KtNamedFunction>(PositioningStrategy.TAILREC_MODIFIER)
val NON_TAIL_RECURSIVE_CALL by warning<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) val NON_TAIL_RECURSIVE_CALL by warning<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
val TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED by warning<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) val TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED by warning<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
} }
@@ -107,6 +107,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
NON_FINAL_MODIFIER_OR_NAME, NON_FINAL_MODIFIER_OR_NAME,
ENUM_MODIFIER, ENUM_MODIFIER,
FIELD_KEYWORD, FIELD_KEYWORD,
TAILREC_MODIFIER,
; ;
@@ -442,8 +442,8 @@ object FirErrors {
val FORBIDDEN_VARARG_PARAMETER_TYPE by error1<KtParameter, ConeKotlinType>(SourceElementPositioningStrategies.PARAMETER_VARARG_MODIFIER) val FORBIDDEN_VARARG_PARAMETER_TYPE by error1<KtParameter, ConeKotlinType>(SourceElementPositioningStrategies.PARAMETER_VARARG_MODIFIER)
val VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION by error0<KtParameter>() val VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION by error0<KtParameter>()
val CANNOT_INFER_PARAMETER_TYPE by error0<KtElement>() val CANNOT_INFER_PARAMETER_TYPE by error0<KtElement>()
val NO_TAIL_CALLS_FOUND by warning0<KtNamedFunction>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) val NO_TAIL_CALLS_FOUND by warning0<KtNamedFunction>(SourceElementPositioningStrategies.TAILREC_MODIFIER)
val TAILREC_ON_VIRTUAL_MEMBER_ERROR by error0<KtNamedFunction>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) val TAILREC_ON_VIRTUAL_MEMBER_ERROR by error0<KtNamedFunction>(SourceElementPositioningStrategies.TAILREC_MODIFIER)
val NON_TAIL_RECURSIVE_CALL by warning0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val NON_TAIL_RECURSIVE_CALL by warning0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED by warning0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED by warning0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
@@ -379,6 +379,9 @@ object LightTreePositioningStrategies {
val ENUM_MODIFIER: LightTreePositioningStrategy = val ENUM_MODIFIER: LightTreePositioningStrategy =
ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.ENUM_KEYWORD)) ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.ENUM_KEYWORD))
val TAILREC_MODIFIER: LightTreePositioningStrategy =
ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.TAILREC_KEYWORD))
val FIELD_KEYWORD: LightTreePositioningStrategy = object : LightTreePositioningStrategy() { val FIELD_KEYWORD: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
override fun mark( override fun mark(
node: LighterASTNode, node: LighterASTNode,
@@ -324,4 +324,9 @@ object SourceElementPositioningStrategies {
LightTreePositioningStrategies.FIELD_KEYWORD, LightTreePositioningStrategies.FIELD_KEYWORD,
PositioningStrategies.FIELD_KEYWORD PositioningStrategies.FIELD_KEYWORD
) )
val TAILREC_MODIFIER = SourceElementPositioningStrategy(
LightTreePositioningStrategies.TAILREC_MODIFIER,
PositioningStrategies.TAILREC_MODIFIER
)
} }
@@ -292,6 +292,9 @@ object PositioningStrategies {
@JvmField @JvmField
val ENUM_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.ENUM_KEYWORD) val ENUM_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.ENUM_KEYWORD)
@JvmField
val TAILREC_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.TAILREC_KEYWORD)
@JvmField @JvmField
val FIELD_KEYWORD: PositioningStrategy<KtBackingField> = object : DeclarationHeader<KtBackingField>() { val FIELD_KEYWORD: PositioningStrategy<KtBackingField> = object : DeclarationHeader<KtBackingField>() {
override fun mark(element: KtBackingField): List<TextRange> { override fun mark(element: KtBackingField): List<TextRange> {
@@ -6,7 +6,7 @@
// DONT_RUN_GENERATED_CODE: JS // DONT_RUN_GENERATED_CODE: JS
// IGNORE_BACKEND: JS // IGNORE_BACKEND: JS
<!NO_TAIL_CALLS_FOUND!>tailrec fun noTails()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun noTails() {
// nothing here // nothing here
} }
@@ -16,7 +16,7 @@ class B {
} }
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun h2(x : Any)<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun h2(x : Any) {
this@B.h2("no recursion") // keep vigilance this@B.h2("no recursion") // keep vigilance
} }
@@ -8,7 +8,7 @@
// DONT_RUN_GENERATED_CODE: JS // DONT_RUN_GENERATED_CODE: JS
// IGNORE_BACKEND: JS // IGNORE_BACKEND: JS
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo() {
bar { bar {
<!NON_TAIL_RECURSIVE_CALL!>foo<!>() <!NON_TAIL_RECURSIVE_CALL!>foo<!>()
} }
@@ -6,7 +6,7 @@
// DONT_RUN_GENERATED_CODE: JS // DONT_RUN_GENERATED_CODE: JS
// IGNORE_BACKEND: JS // IGNORE_BACKEND: JS
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo() {
fun bar() { fun bar() {
<!NON_TAIL_RECURSIVE_CALL!>foo<!>() <!NON_TAIL_RECURSIVE_CALL!>foo<!>()
} }
@@ -6,7 +6,7 @@
// DONT_RUN_GENERATED_CODE: JS // DONT_RUN_GENERATED_CODE: JS
// IGNORE_BACKEND: JS // IGNORE_BACKEND: JS
<!NO_TAIL_CALLS_FOUND!>tailrec fun test(counter : Int) : Int<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
if (counter == 0) return 0 if (counter == 0) return 0
try { try {
@@ -6,7 +6,7 @@
// DONT_RUN_GENERATED_CODE: JS // DONT_RUN_GENERATED_CODE: JS
// IGNORE_BACKEND: JS // IGNORE_BACKEND: JS
<!NO_TAIL_CALLS_FOUND!>tailrec fun test(counter : Int) : Int<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
if (counter == 0) return 0 if (counter == 0) return 0
try { try {
@@ -6,7 +6,7 @@
// DONT_RUN_GENERATED_CODE: JS // DONT_RUN_GENERATED_CODE: JS
// IGNORE_BACKEND: JS // IGNORE_BACKEND: JS
<!NO_TAIL_CALLS_FOUND!>tailrec fun test(counter : Int) : Int<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
if (counter == 0) return 0 if (counter == 0) return 0
try { try {
@@ -6,7 +6,7 @@
// DONT_RUN_GENERATED_CODE: JS // DONT_RUN_GENERATED_CODE: JS
// IGNORE_BACKEND: JS // IGNORE_BACKEND: JS
<!NO_TAIL_CALLS_FOUND!>tailrec fun test(counter : Int) : Int<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
if (counter == 0) return 0 if (counter == 0) return 0
try { try {
@@ -6,7 +6,7 @@
// DONT_RUN_GENERATED_CODE: JS // DONT_RUN_GENERATED_CODE: JS
// IGNORE_BACKEND: JS // IGNORE_BACKEND: JS
<!NO_TAIL_CALLS_FOUND!>tailrec fun test(go: Boolean) : Unit<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(go: Boolean) : Unit {
if (!go) return if (!go) return
try { try {
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>test<!>(false) <!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>test<!>(false)
@@ -19,7 +19,7 @@ class A {
} }
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun f3(a : A)<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun f3(a : A) {
a.<!NON_TAIL_RECURSIVE_CALL!>f3<!>(a) // non-tail recursion, could be potentially resolved by condition if (a == this) f3() else a.f3() a.<!NON_TAIL_RECURSIVE_CALL!>f3<!>(a) // non-tail recursion, could be potentially resolved by condition if (a == this) f3() else a.f3()
} }
} }
+10 -10
View File
@@ -2,17 +2,17 @@
// WITH_STDLIB // WITH_STDLIB
// !DIAGNOSTICS: -UNREACHABLE_CODE // !DIAGNOSTICS: -UNREACHABLE_CODE
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo1()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo1() {
<!NON_TAIL_RECURSIVE_CALL!>foo1<!>() <!NON_TAIL_RECURSIVE_CALL!>foo1<!>()
1 1
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo2()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo2() {
<!NON_TAIL_RECURSIVE_CALL!>foo2<!>() <!NON_TAIL_RECURSIVE_CALL!>foo2<!>()
val i = 1 val i = 1
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo3()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo3() {
<!NON_TAIL_RECURSIVE_CALL!>foo3<!>() <!NON_TAIL_RECURSIVE_CALL!>foo3<!>()
foo1() foo1()
} }
@@ -27,7 +27,7 @@ tailrec fun foo5() {
foo4() foo4()
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo6(b: Boolean)<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo6(b: Boolean) {
while (b) { while (b) {
<!NON_TAIL_RECURSIVE_CALL!>foo6<!>(!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) { while (true) {
<!NON_TAIL_RECURSIVE_CALL!>foo7_break<!>() <!NON_TAIL_RECURSIVE_CALL!>foo7_break<!>()
break break
} }
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo7_continue()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo7_continue() {
while (true) { while (true) {
<!NON_TAIL_RECURSIVE_CALL!>foo7_continue<!>() <!NON_TAIL_RECURSIVE_CALL!>foo7_continue<!>()
continue continue
} }
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo8()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo8() {
while (true) { while (true) {
<!NON_TAIL_RECURSIVE_CALL!>foo8<!>() <!NON_TAIL_RECURSIVE_CALL!>foo8<!>()
throw Exception() throw Exception()
@@ -62,19 +62,19 @@ tailrec fun foo7_return() {
foo8() foo8()
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo9()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo9() {
<!NON_TAIL_RECURSIVE_CALL!>foo9<!>() <!NON_TAIL_RECURSIVE_CALL!>foo9<!>()
fun bar() {} fun bar() {}
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo10()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo10() {
<!NON_TAIL_RECURSIVE_CALL!>foo10<!>() <!NON_TAIL_RECURSIVE_CALL!>foo10<!>()
class Bar { class Bar {
val i = 1 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<!>()}" return "hello ${<!NON_TAIL_RECURSIVE_CALL!>foo11<!>()}"
} }
@@ -1,6 +1,6 @@
// WITH_STDLIB // WITH_STDLIB
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo1()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo1() {
run { run {
<!NON_TAIL_RECURSIVE_CALL!>foo1<!>() <!NON_TAIL_RECURSIVE_CALL!>foo1<!>()
} }
@@ -9,13 +9,13 @@
fun myRun(f: () -> Unit) = f() fun myRun(f: () -> Unit) = f()
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo2()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo2() {
myRun { myRun {
<!NON_TAIL_RECURSIVE_CALL!>foo2<!>() <!NON_TAIL_RECURSIVE_CALL!>foo2<!>()
} }
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo3()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo3() {
fun bar() { fun bar() {
<!NON_TAIL_RECURSIVE_CALL!>foo3<!>() <!NON_TAIL_RECURSIVE_CALL!>foo3<!>()
} }
@@ -23,14 +23,14 @@ fun myRun(f: () -> Unit) = f()
} }
class A { class A {
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo4()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo4() {
with(this) { with(this) {
<!NON_TAIL_RECURSIVE_CALL!>foo4<!>() <!NON_TAIL_RECURSIVE_CALL!>foo4<!>()
} }
} }
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo5()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo5() {
run { run {
return <!NON_TAIL_RECURSIVE_CALL!>foo5<!>() return <!NON_TAIL_RECURSIVE_CALL!>foo5<!>()
} }
+4 -4
View File
@@ -1,5 +1,5 @@
// FIR_IDENTICAL // FIR_IDENTICAL
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo1()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo1() {
try { try {
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo1<!>() <!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo1<!>()
} catch (e: Exception) { } catch (e: Exception) {
@@ -9,7 +9,7 @@
} }
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo2()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo2() {
try { try {
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo2<!>() <!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo2<!>()
foo1() foo1()
@@ -22,7 +22,7 @@
} }
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo3()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo3() {
try { try {
try { try {
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo3<!>() <!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 { try {
if (true) { if (true) {
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo4<!>() <!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo4<!>()
@@ -1,15 +1,15 @@
//!LANGUAGE: -ProhibitTailrecOnVirtualMember //!LANGUAGE: -ProhibitTailrecOnVirtualMember
open class A { 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) 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) 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) baz(y)
} }
@@ -38,15 +38,15 @@ open class B : A() {
open class C : 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) 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) 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) baz(y)
} }
} }
@@ -66,15 +66,15 @@ object D : A() {
} }
sealed class E : 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) 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) 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) 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) 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) 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) baz(y)
} }
@@ -134,15 +134,15 @@ enum class G {
G1; 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) 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) 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) baz(y)
} }
@@ -2,15 +2,15 @@
//!LANGUAGE: +ProhibitTailrecOnVirtualMember //!LANGUAGE: +ProhibitTailrecOnVirtualMember
open class A { 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) 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) 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) baz(y)
} }
@@ -39,15 +39,15 @@ open class B : A() {
open class C : 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) 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) 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) baz(y)
} }
} }
@@ -67,15 +67,15 @@ object D : A() {
} }
sealed class E : 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) 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) 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) 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) 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) 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) baz(y)
} }
@@ -135,15 +135,15 @@ enum class G {
G1; 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) 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) 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) baz(y)
} }
@@ -6,11 +6,11 @@ open class A {
} }
class B: 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<!>() <!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) <!NON_TAIL_RECURSIVE_CALL!>gav<!>(y)
} }
@@ -44,7 +44,7 @@ enum class E {
} }
}, },
C { 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`. C.rec() // resolution goes to `E.rec`. Hence the resolved symbol is considered different from `C.rec`.
} }
}; };
@@ -1,6 +1,6 @@
// FIR_IDENTICAL // FIR_IDENTICAL
class A(val a: A) { 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<!>() a.<!NON_TAIL_RECURSIVE_CALL!>foo1<!>()
} }
@@ -12,7 +12,7 @@ class A(val a: A) {
foo3() foo3()
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo4()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo4() {
with(a) { with(a) {
<!NON_TAIL_RECURSIVE_CALL!>foo4<!>() <!NON_TAIL_RECURSIVE_CALL!>foo4<!>()
return return
@@ -7,7 +7,7 @@ tailrec fun String.foo2() {
this.foo2() this.foo2()
} }
<!NO_TAIL_CALLS_FOUND!>tailrec fun String.foo3()<!> { <!NO_TAIL_CALLS_FOUND!>tailrec<!> fun String.foo3() {
with(this) { with(this) {
<!NON_TAIL_RECURSIVE_CALL!>foo3<!>() <!NON_TAIL_RECURSIVE_CALL!>foo3<!>()
} }
@@ -5,7 +5,7 @@ object O {
} }
class A { 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 { companion object {
fun foo(i: Int) = 42 + i fun foo(i: Int) = 42 + i
@@ -13,5 +13,5 @@ class A {
} }
class B { 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)
} }