diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTailrecFunctionChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTailrecFunctionChecker.kt index 5adce113c7a..b0799223f5f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTailrecFunctionChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTailrecFunctionChecker.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration +import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.analysis.cfa.util.TraverseDirection import org.jetbrains.kotlin.fir.analysis.cfa.util.traverse import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext @@ -14,6 +15,7 @@ import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.utils.isOverride import org.jetbrains.kotlin.fir.declarations.utils.isTailRec +import org.jetbrains.kotlin.fir.declarations.utils.visibility import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression import org.jetbrains.kotlin.fir.expressions.arguments import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression @@ -27,7 +29,7 @@ import org.jetbrains.kotlin.fir.types.toSymbol object FirTailrecFunctionChecker : FirSimpleFunctionChecker() { override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) { if (!declaration.isTailRec) return - if (!declaration.isEffectivelyFinal(context)) { + if (!(declaration.isEffectivelyFinal(context) || declaration.visibility == Visibilities.Private)) { reporter.reportOn(declaration.source, FirErrors.TAILREC_ON_VIRTUAL_MEMBER_ERROR, context) } val graph = declaration.controlFlowGraphReference?.controlFlowGraph ?: return diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrType.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrType.kt index 2930e0a72f9..d8d3fef0406 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrType.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrType.kt @@ -100,4 +100,4 @@ interface IrTypeAbbreviation : IrAnnotationContainer { val typeAlias: IrTypeAliasSymbol val hasQuestionMark: Boolean val arguments: List -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/tailRecOnVirtualMember.fir.kt b/compiler/testData/diagnostics/tests/tailRecOnVirtualMember.fir.kt index e8d6e056dc3..cc7ce99eb72 100644 --- a/compiler/testData/diagnostics/tests/tailRecOnVirtualMember.fir.kt +++ b/compiler/testData/diagnostics/tests/tailRecOnVirtualMember.fir.kt @@ -17,6 +17,10 @@ open class A { boo(y) } + private open tailrec fun booOpen(y: Int) { + booOpen(y) + } + internal tailrec fun baa(y: Int) { baa(y) } diff --git a/compiler/testData/diagnostics/tests/tailRecOnVirtualMember.kt b/compiler/testData/diagnostics/tests/tailRecOnVirtualMember.kt index 5bc69f137b0..b0da96e7aa8 100644 --- a/compiler/testData/diagnostics/tests/tailRecOnVirtualMember.kt +++ b/compiler/testData/diagnostics/tests/tailRecOnVirtualMember.kt @@ -17,6 +17,10 @@ open class A { boo(y) } + private open tailrec fun booOpen(y: Int) { + booOpen(y) + } + internal tailrec fun baa(y: Int) { baa(y) } diff --git a/compiler/testData/diagnostics/tests/tailRecOnVirtualMember.txt b/compiler/testData/diagnostics/tests/tailRecOnVirtualMember.txt index 478a5ef3118..69a27dbf922 100644 --- a/compiler/testData/diagnostics/tests/tailRecOnVirtualMember.txt +++ b/compiler/testData/diagnostics/tests/tailRecOnVirtualMember.txt @@ -8,6 +8,7 @@ public open class A { internal open tailrec fun bar(/*0*/ y: kotlin.Int): kotlin.Unit protected open tailrec fun baz(/*0*/ y: kotlin.Int): kotlin.Unit private final tailrec fun boo(/*0*/ y: kotlin.Int): kotlin.Unit + private open tailrec fun booOpen(/*0*/ y: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open tailrec fun foo(/*0*/ x: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @@ -20,6 +21,7 @@ public open class B : A { internal final override /*1*/ tailrec fun bar(/*0*/ y: kotlin.Int): kotlin.Unit protected final override /*1*/ tailrec fun baz(/*0*/ y: kotlin.Int): kotlin.Unit invisible_fake final override /*1*/ tailrec /*fake_override*/ fun boo(/*0*/ y: kotlin.Int): kotlin.Unit + invisible_fake open override /*1*/ tailrec /*fake_override*/ fun booOpen(/*0*/ y: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public final override /*1*/ tailrec fun foo(/*0*/ x: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @@ -32,6 +34,7 @@ public open class C : A { internal open override /*1*/ tailrec fun bar(/*0*/ y: kotlin.Int): kotlin.Unit protected open override /*1*/ tailrec fun baz(/*0*/ y: kotlin.Int): kotlin.Unit invisible_fake final override /*1*/ tailrec /*fake_override*/ fun boo(/*0*/ y: kotlin.Int): kotlin.Unit + invisible_fake open override /*1*/ tailrec /*fake_override*/ fun booOpen(/*0*/ y: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ tailrec fun foo(/*0*/ x: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @@ -44,6 +47,7 @@ public object D : A { internal open override /*1*/ tailrec fun bar(/*0*/ y: kotlin.Int): kotlin.Unit protected open override /*1*/ tailrec fun baz(/*0*/ y: kotlin.Int): kotlin.Unit invisible_fake final override /*1*/ tailrec /*fake_override*/ fun boo(/*0*/ y: kotlin.Int): kotlin.Unit + invisible_fake open override /*1*/ tailrec /*fake_override*/ fun booOpen(/*0*/ y: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ tailrec fun foo(/*0*/ x: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @@ -56,6 +60,7 @@ public sealed class E : A { internal open override /*1*/ tailrec fun bar(/*0*/ y: kotlin.Int): kotlin.Unit protected open override /*1*/ tailrec fun baz(/*0*/ y: kotlin.Int): kotlin.Unit invisible_fake final override /*1*/ tailrec /*fake_override*/ fun boo(/*0*/ y: kotlin.Int): kotlin.Unit + invisible_fake open override /*1*/ tailrec /*fake_override*/ fun booOpen(/*0*/ y: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ tailrec fun foo(/*0*/ x: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int @@ -67,6 +72,7 @@ public sealed class E : A { internal open override /*1*/ tailrec fun bar(/*0*/ y: kotlin.Int): kotlin.Unit protected open override /*1*/ tailrec fun baz(/*0*/ y: kotlin.Int): kotlin.Unit invisible_fake final override /*1*/ tailrec /*fake_override*/ fun boo(/*0*/ y: kotlin.Int): kotlin.Unit + invisible_fake open override /*1*/ tailrec /*fake_override*/ fun booOpen(/*0*/ y: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ tailrec fun foo(/*0*/ x: kotlin.Int): kotlin.Unit public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int