FIR Checker: check tailrec
Difference from FE1.0 * KT-4285: calls to virtual method with default argument should be reported as not tailrec. FE1.0 is missing such cases. * KT-48600: calls inside lambda should be reported as not tailrec. FE1.0 also misses such cases.
This commit is contained in:
committed by
TeamCityServer
parent
5df316a129
commit
8525b4932b
+36
@@ -770,6 +770,24 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/SyntaxErrorInTestHighlightingEof.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecBasic.kt")
|
||||
public void testTailRecBasic() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecBasic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecInNestedScopes.kt")
|
||||
public void testTailRecInNestedScopes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecInNestedScopes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecInTry.kt")
|
||||
public void testTailRecInTry() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecInTry.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecOnVirtualMember.kt")
|
||||
public void testTailRecOnVirtualMember() throws Exception {
|
||||
@@ -788,6 +806,24 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecOverridden.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecSingleton.kt")
|
||||
public void testTailRecSingleton() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecSingleton.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecWithDispatchReceiver.kt")
|
||||
public void testTailRecWithDispatchReceiver() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecWithDispatchReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecWithExtensionReceiver.kt")
|
||||
public void testTailRecWithExtensionReceiver() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecWithExtensionReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecursionComplex.kt")
|
||||
public void testTailRecursionComplex() throws Exception {
|
||||
|
||||
+36
@@ -770,6 +770,24 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/SyntaxErrorInTestHighlightingEof.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecBasic.kt")
|
||||
public void testTailRecBasic() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecBasic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecInNestedScopes.kt")
|
||||
public void testTailRecInNestedScopes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecInNestedScopes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecInTry.kt")
|
||||
public void testTailRecInTry() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecInTry.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecOnVirtualMember.kt")
|
||||
public void testTailRecOnVirtualMember() throws Exception {
|
||||
@@ -788,6 +806,24 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecOverridden.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecSingleton.kt")
|
||||
public void testTailRecSingleton() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecSingleton.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecWithDispatchReceiver.kt")
|
||||
public void testTailRecWithDispatchReceiver() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecWithDispatchReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecWithExtensionReceiver.kt")
|
||||
public void testTailRecWithExtensionReceiver() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecWithExtensionReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecursionComplex.kt")
|
||||
public void testTailRecursionComplex() throws Exception {
|
||||
|
||||
+5
@@ -809,6 +809,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
|
||||
// TODO: replace with KtParameter
|
||||
val CANNOT_INFER_PARAMETER_TYPE by error<KtElement>()
|
||||
|
||||
val NO_TAIL_CALLS_FOUND by warning<KtNamedFunction>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
val TAILREC_ON_VIRTUAL_MEMBER_ERROR by error<KtNamedFunction>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
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 FUN_INTERFACES by object : DiagnosticGroup("Fun interfaces") {
|
||||
|
||||
@@ -66,6 +66,7 @@ import org.jetbrains.kotlin.psi.KtImportDirective
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
|
||||
@@ -438,6 +439,10 @@ object FirErrors {
|
||||
val FORBIDDEN_VARARG_PARAMETER_TYPE by error1<KtParameter, ConeKotlinType>(SourceElementPositioningStrategies.PARAMETER_VARARG_MODIFIER)
|
||||
val VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION by error0<KtParameter>()
|
||||
val CANNOT_INFER_PARAMETER_TYPE by error0<KtElement>()
|
||||
val NO_TAIL_CALLS_FOUND by warning0<KtNamedFunction>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val TAILREC_ON_VIRTUAL_MEMBER_ERROR by error0<KtNamedFunction>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
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)
|
||||
|
||||
// Fun interfaces
|
||||
val FUN_INTERFACE_CONSTRUCTOR_REFERENCE by error0<KtExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
|
||||
+1
@@ -43,6 +43,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirFunctionNameChecker,
|
||||
FirFunctionTypeParametersSyntaxChecker,
|
||||
FirOperatorModifierChecker,
|
||||
FirTailrecFunctionChecker,
|
||||
)
|
||||
|
||||
override val propertyCheckers: Set<FirPropertyChecker>
|
||||
|
||||
+10
@@ -45,6 +45,16 @@ private inline fun isInsideSpecificClass(
|
||||
context.containingDeclarations.asReversed().any { it is FirRegularClass && predicate.invoke(it) }
|
||||
}
|
||||
|
||||
internal fun FirMemberDeclaration.isEffectivelyFinal(context: CheckerContext): Boolean {
|
||||
if (this.isFinal) return true
|
||||
val containingClass = context.containingDeclarations.lastOrNull() as? FirRegularClass ?: return true
|
||||
if (containingClass.isEnumClass) {
|
||||
// Enum class has enum entries and hence is not considered final.
|
||||
return false
|
||||
}
|
||||
return containingClass.isFinal
|
||||
}
|
||||
|
||||
internal fun FirMemberDeclaration.isEffectivelyExpect(
|
||||
containingClass: FirClass?,
|
||||
context: CheckerContext,
|
||||
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.cfa.TraverseDirection
|
||||
import org.jetbrains.kotlin.fir.analysis.cfa.traverse
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.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.expressions.FirThisReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.arguments
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.controlFlowGraph
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
|
||||
object FirTailrecFunctionChecker : FirSimpleFunctionChecker() {
|
||||
override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!declaration.isTailRec) return
|
||||
if (!declaration.isEffectivelyFinal(context)) {
|
||||
reporter.reportOn(declaration.source, FirErrors.TAILREC_ON_VIRTUAL_MEMBER_ERROR, context)
|
||||
}
|
||||
val graph = declaration.controlFlowGraphReference?.controlFlowGraph ?: return
|
||||
|
||||
var tryScopeCount = 0
|
||||
var catchScopeCount = 0
|
||||
var finallyScopeCount = 0
|
||||
var tailrecCount = 0
|
||||
var lambdaScopeCount = 0
|
||||
graph.traverse(TraverseDirection.Forward, object : ControlFlowGraphVisitorVoid() {
|
||||
override fun visitNode(node: CFGNode<*>) {}
|
||||
override fun visitPostponedLambdaEnterNode(node: PostponedLambdaEnterNode) {
|
||||
lambdaScopeCount++
|
||||
}
|
||||
|
||||
override fun visitPostponedLambdaExitNode(node: PostponedLambdaExitNode) {
|
||||
lambdaScopeCount--
|
||||
}
|
||||
|
||||
override fun visitTryMainBlockEnterNode(node: TryMainBlockEnterNode) {
|
||||
tryScopeCount++
|
||||
}
|
||||
|
||||
override fun visitTryMainBlockExitNode(node: TryMainBlockExitNode) {
|
||||
tryScopeCount--
|
||||
}
|
||||
|
||||
override fun visitCatchClauseEnterNode(node: CatchClauseEnterNode) {
|
||||
catchScopeCount++
|
||||
}
|
||||
|
||||
override fun visitCatchClauseExitNode(node: CatchClauseExitNode) {
|
||||
catchScopeCount--
|
||||
}
|
||||
|
||||
override fun visitFinallyBlockEnterNode(node: FinallyBlockEnterNode) {
|
||||
finallyScopeCount++
|
||||
}
|
||||
|
||||
override fun visitFinallyBlockExitNode(node: FinallyBlockExitNode) {
|
||||
finallyScopeCount--
|
||||
}
|
||||
|
||||
override fun visitFunctionCallNode(node: FunctionCallNode) {
|
||||
val functionCall = node.fir
|
||||
val resolvedSymbol = functionCall.calleeReference.toResolvedCallableSymbol() as? FirNamedFunctionSymbol ?: return
|
||||
if (resolvedSymbol != declaration.symbol) return
|
||||
if (functionCall.arguments.size != resolvedSymbol.valueParameterSymbols.size && resolvedSymbol.isOverride) {
|
||||
// Overridden functions using default arguments at tail call are not included: KT-4285
|
||||
reporter.reportOn(functionCall.source, FirErrors.NON_TAIL_RECURSIVE_CALL, context)
|
||||
return
|
||||
}
|
||||
val dispatchReceiver = functionCall.dispatchReceiver
|
||||
// A tailrec call does not support changing dispatchers. Here we report changing dispatch receiver if the dispatch receiver
|
||||
// is present and not a `this`. For the `this` check, we don't need to actually compare if the dispatch receiver `this`
|
||||
// references the same `this` made available from `declaration`. This is because
|
||||
// 1. if `this` is not labeled, then it references the innermost `this` receiver. If the innermost scope is not the
|
||||
// `declaration` body, then follow-up checks on following nodes would report there to be more instructions, which would
|
||||
// then make this call non-tailrec.
|
||||
// 2. If `this` is labeled, then one of the following is possible.
|
||||
// a. the call is in some context that has additional implicit `this` declared. But this can only happen if the call is
|
||||
// placed inside some extension lambda, which would be covered by the later check on exiting node.
|
||||
// b. `declaration` is a member function in a local class and the receiver is a labeled `this` pointing to the outer
|
||||
// non-local class. In this case, the resolved symbol cannot be the same as the symbol of `declaration`, and this case
|
||||
// is already bailed out earlier. So there is no need to report anything.
|
||||
// c. `declaration` is a member function of an inner class and the receiver is a labeled `this` pointing to the outer
|
||||
// class. The reasoning is the same with b.
|
||||
// Also note that if the dispatch receiver is explicitly specify to be a singleton, the call is not compiled as a tailrec
|
||||
// either. See KT-48602.
|
||||
if (dispatchReceiver !is FirThisReceiverExpression && dispatchReceiver !is FirNoReceiverExpression) {
|
||||
reporter.reportOn(functionCall.source, FirErrors.NON_TAIL_RECURSIVE_CALL, context)
|
||||
return
|
||||
}
|
||||
if (tryScopeCount > 0 || catchScopeCount > 0 || finallyScopeCount > 0) {
|
||||
reporter.reportOn(functionCall.source, FirErrors.TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED, context)
|
||||
} else if (lambdaScopeCount > 0 || node.hasMoreFollowingInstructions(declaration)) {
|
||||
reporter.reportOn(functionCall.source, FirErrors.NON_TAIL_RECURSIVE_CALL, context)
|
||||
} else if (!node.isDead) {
|
||||
tailrecCount++
|
||||
}
|
||||
}
|
||||
})
|
||||
if (tailrecCount == 0) {
|
||||
reporter.reportOn(declaration.source, FirErrors.NO_TAIL_CALLS_FOUND, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun CFGNode<*>.hasMoreFollowingInstructions(tailrecFunction: FirSimpleFunction): Boolean {
|
||||
for (next in followingNodes) {
|
||||
val edge = outgoingEdges.getValue(next)
|
||||
if (!edge.kind.usedInCfa || edge.kind.isDead) continue
|
||||
if (edge.kind.isBack) return true
|
||||
val hasMore = when (next) {
|
||||
// If exiting another function, then it means this call is inside a nested local function, in which case, it's not a tailrec call.
|
||||
is FunctionExitNode -> return next.fir != tailrecFunction
|
||||
is JumpNode, is BinaryAndExitNode, is BinaryOrExitNode, is WhenBranchResultExitNode, is WhenExitNode, is BlockExitNode ->
|
||||
next.hasMoreFollowingInstructions(tailrecFunction)
|
||||
else -> return true
|
||||
}
|
||||
if (hasMore) return hasMore
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
+8
@@ -298,6 +298,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_MODIFIER_FORM
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_PRIVATE_CONSTRUCTOR_IN_ENUM
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_PRIVATE_OR_PROTECTED_CONSTRUCTOR_IN_SEALED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_TAIL_RECURSIVE_CALL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_VARARG_SPREAD
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOTHING_TO_INLINE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOTHING_TO_OVERRIDE
|
||||
@@ -315,6 +316,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_GET_METHOD
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_RECEIVER_ALLOWED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_SET_METHOD
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_TAIL_CALLS_FOUND
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_THIS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_VALUE_FOR_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NULLABLE_INLINE_PARAMETER
|
||||
@@ -418,6 +420,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPER_CALL_FROM_P
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPER_IS_NOT_AN_EXPRESSION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SUPER_NOT_AVAILABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.SYNTAX
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TAILREC_ON_VIRTUAL_MEMBER_ERROR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.THROWABLE_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOO_MANY_ARGUMENTS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOPLEVEL_TYPEALIASES_ONLY
|
||||
@@ -1218,6 +1222,10 @@ class FirDefaultErrorMessages {
|
||||
map.put(FORBIDDEN_VARARG_PARAMETER_TYPE, "Forbidden vararg parameter type: {0}", RENDER_TYPE)
|
||||
map.put(VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION, "A type annotation is required on a value parameter")
|
||||
map.put(CANNOT_INFER_PARAMETER_TYPE, "cannot infer a type for this parameter. Please specify it explicitly.")
|
||||
map.put(NO_TAIL_CALLS_FOUND, "A function is marked as tail-recursive but no tail calls are found.")
|
||||
map.put(TAILREC_ON_VIRTUAL_MEMBER_ERROR, "Tailrec is not allowed on open members");
|
||||
map.put(NON_TAIL_RECURSIVE_CALL, "Recursive call is not a tail call");
|
||||
map.put(TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED, "Tail recursion optimization inside try/catch/finally is not supported");
|
||||
|
||||
// Fun interfaces
|
||||
map.put(FUN_INTERFACE_CONSTRUCTOR_REFERENCE, "Functional/SAM interface constructor references are prohibited")
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun noTails()<!> {
|
||||
// nothing here
|
||||
|
||||
-1
@@ -7,7 +7,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
class B {
|
||||
inner class C {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
tailrec fun test(x : Int) : Int {
|
||||
var z = if (x > 3) 3 else x
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
tailrec fun test(x : Int) : Int {
|
||||
if (x == 1) {
|
||||
|
||||
Vendored
+1
@@ -1,5 +1,6 @@
|
||||
// KT-16549
|
||||
// IGNORE_BACKEND: JVM
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
class TailInline {
|
||||
private inline fun act(action: () -> Unit) {
|
||||
|
||||
+1
@@ -1,6 +1,7 @@
|
||||
// KT-14961
|
||||
// IGNORE_BACKEND: JVM, JS_IR, WASM
|
||||
// WITH_RUNTIME
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
fun listOfFactor(number: Int): List<Int> {
|
||||
tailrec fun listOfFactor(number: Int, acc: List<Int>): List<Int> {
|
||||
|
||||
-1
@@ -7,7 +7,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo()<!> {
|
||||
bar {
|
||||
|
||||
Vendored
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo()<!> {
|
||||
fun bar() {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
tailrec fun test(x : Int) : Int {
|
||||
return if (x == 1) {
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun test(counter : Int) : Int<!> {
|
||||
if (counter == 0) return 0
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun test(counter : Int) : Int<!> {
|
||||
if (counter == 0) return 0
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun test(counter : Int) : Int<!> {
|
||||
if (counter == 0) return 0
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun test(counter : Int) : Int<!> {
|
||||
if (counter == 0) return 0
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
tailrec fun test(x : Int) : Int =
|
||||
if (x == 1) {
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
tailrec fun test(x : Int) : Int {
|
||||
if (x == 10) {
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
tailrec fun test(x : Int) : Int {
|
||||
if (x == 0) {
|
||||
|
||||
Vendored
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun test(go: Boolean) : Unit<!> {
|
||||
if (!go) return
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
class A {
|
||||
tailrec fun f1(c : Int) {
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
tailrec fun test(x : Int) : Unit {
|
||||
if (x == 1) {
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
tailrec fun withWhen(counter : Int) : Int =
|
||||
when (counter) {
|
||||
|
||||
-1
@@ -7,7 +7,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
tailrec fun withWhen(counter : Int, d : Any) : Int =
|
||||
when (counter) {
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
tailrec fun withWhen2(counter : Int) : Int =
|
||||
when {
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_STDLIB
|
||||
// !DIAGNOSTICS: -UNREACHABLE_CODE
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo1()<!> {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo1<!>()
|
||||
1
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo2()<!> {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo2<!>()
|
||||
val i = 1
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo3()<!> {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo3<!>()
|
||||
foo1()
|
||||
}
|
||||
|
||||
tailrec fun foo4() {
|
||||
if (true) foo4()
|
||||
else foo3()
|
||||
}
|
||||
|
||||
tailrec fun foo5() {
|
||||
return foo5()
|
||||
foo4()
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo6(b: Boolean)<!> {
|
||||
while (b) {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo6<!>(!b)
|
||||
}
|
||||
}
|
||||
|
||||
tailrec fun foo7_return() {
|
||||
while (true) {
|
||||
foo7_return()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
<!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()<!> {
|
||||
while (true) {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo7_continue<!>()
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo8()<!> {
|
||||
while (true) {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo8<!>()
|
||||
throw Exception()
|
||||
}
|
||||
foo8()
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo9()<!> {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo9<!>()
|
||||
fun bar() {}
|
||||
}
|
||||
|
||||
<!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<!> {
|
||||
return "hello ${<!NON_TAIL_RECURSIVE_CALL!>foo11<!>()}"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package
|
||||
|
||||
public tailrec fun foo1(): kotlin.Unit
|
||||
public tailrec fun foo10(): kotlin.Unit
|
||||
public tailrec fun foo11(): kotlin.String
|
||||
public tailrec fun foo2(): kotlin.Unit
|
||||
public tailrec fun foo3(): kotlin.Unit
|
||||
public tailrec fun foo4(): kotlin.Unit
|
||||
public tailrec fun foo5(): kotlin.Unit
|
||||
public tailrec fun foo6(/*0*/ b: kotlin.Boolean): kotlin.Unit
|
||||
public tailrec fun foo7_break(): kotlin.Unit
|
||||
public tailrec fun foo7_continue(): kotlin.Unit
|
||||
public tailrec fun foo7_return(): kotlin.Unit
|
||||
public tailrec fun foo8(): kotlin.Unit
|
||||
public tailrec fun foo9(): kotlin.Unit
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// WITH_STDLIB
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo1()<!> {
|
||||
run {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo1<!>()
|
||||
}
|
||||
}
|
||||
|
||||
fun myRun(f: () -> Unit) = f()
|
||||
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo2()<!> {
|
||||
myRun {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo2<!>()
|
||||
}
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo3()<!> {
|
||||
fun bar() {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo3<!>()
|
||||
}
|
||||
bar()
|
||||
}
|
||||
|
||||
class A {
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo4()<!> {
|
||||
with(this) {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo4<!>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo5()<!> {
|
||||
run {
|
||||
return <!NON_TAIL_RECURSIVE_CALL!>foo5<!>()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// WITH_STDLIB
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo1()<!> {
|
||||
run {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo1<!>()
|
||||
}
|
||||
}
|
||||
|
||||
fun myRun(f: () -> Unit) = f()
|
||||
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo2()<!> {
|
||||
myRun {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo2<!>()
|
||||
}
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo3()<!> {
|
||||
fun bar() {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo3<!>()
|
||||
}
|
||||
bar()
|
||||
}
|
||||
|
||||
class A {
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo4()<!> {
|
||||
with(this) {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo4<!>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tailrec fun foo5() {
|
||||
run {
|
||||
return foo5()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package
|
||||
|
||||
public tailrec fun foo1(): kotlin.Unit
|
||||
public tailrec fun foo2(): kotlin.Unit
|
||||
public tailrec fun foo3(): kotlin.Unit
|
||||
public tailrec fun foo5(): kotlin.Unit
|
||||
public fun myRun(/*0*/ f: () -> kotlin.Unit): kotlin.Unit
|
||||
|
||||
public final class A {
|
||||
public constructor A()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final tailrec fun foo4(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// FIR_IDENTICAL
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo1()<!> {
|
||||
try {
|
||||
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo1<!>()
|
||||
} catch (e: Exception) {
|
||||
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo1<!>()
|
||||
} finally {
|
||||
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo1<!>()
|
||||
}
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo2()<!> {
|
||||
try {
|
||||
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo2<!>()
|
||||
foo1()
|
||||
} catch (e: Exception) {
|
||||
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo2<!>()
|
||||
foo1()
|
||||
} finally {
|
||||
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo2<!>()
|
||||
foo1()
|
||||
}
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo3()<!> {
|
||||
try {
|
||||
try {
|
||||
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo3<!>()
|
||||
} finally {
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo3<!>()
|
||||
} finally {
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo3<!>()
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo4()<!> {
|
||||
try {
|
||||
if (true) {
|
||||
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo4<!>()
|
||||
} else {
|
||||
foo1()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (true) {
|
||||
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo4<!>()
|
||||
} else {
|
||||
foo1()
|
||||
}
|
||||
} finally {
|
||||
if (true) {
|
||||
<!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>foo4<!>()
|
||||
} else {
|
||||
foo1()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package
|
||||
|
||||
public tailrec fun foo1(): kotlin.Unit
|
||||
public tailrec fun foo2(): kotlin.Unit
|
||||
public tailrec fun foo3(): kotlin.Unit
|
||||
public tailrec fun foo4(): kotlin.Unit
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
//!LANGUAGE: -ProhibitTailrecOnVirtualMember
|
||||
|
||||
open class A {
|
||||
tailrec open fun foo(x: Int) {
|
||||
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec open fun foo(x: Int)<!> {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
internal tailrec open fun bar(y: Int) {
|
||||
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>internal tailrec open fun bar(y: Int)<!> {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
protected tailrec open fun baz(y: Int) {
|
||||
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>protected tailrec open fun baz(y: Int)<!> {
|
||||
baz(y)
|
||||
}
|
||||
|
||||
@@ -38,15 +38,15 @@ open class B : A() {
|
||||
|
||||
|
||||
open class C : A() {
|
||||
tailrec override fun foo(x: Int) {
|
||||
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun foo(x: Int)<!> {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
tailrec override fun bar(y: Int) {
|
||||
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun bar(y: Int)<!> {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
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 override fun foo(x: Int) {
|
||||
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun foo(x: Int)<!> {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
tailrec override fun bar(y: Int) {
|
||||
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec override fun bar(y: Int)<!> {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
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 open fun foo(x: Int) {
|
||||
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec open fun foo(x: Int)<!> {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
internal tailrec open fun bar(y: Int) {
|
||||
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>internal tailrec open fun bar(y: Int)<!> {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
protected tailrec open fun baz(y: Int) {
|
||||
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>protected tailrec open fun baz(y: Int)<!> {
|
||||
baz(y)
|
||||
}
|
||||
|
||||
@@ -134,15 +134,15 @@ enum class G {
|
||||
|
||||
G1;
|
||||
|
||||
tailrec open fun foo(x: Int) {
|
||||
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>tailrec open fun foo(x: Int)<!> {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
internal tailrec open fun bar(y: Int) {
|
||||
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>internal tailrec open fun bar(y: Int)<!> {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
protected tailrec open fun baz(y: Int) {
|
||||
<!TAILREC_ON_VIRTUAL_MEMBER_ERROR!>protected tailrec open fun baz(y: Int)<!> {
|
||||
baz(y)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
//!LANGUAGE: +ProhibitTailrecOnVirtualMember
|
||||
|
||||
open class A {
|
||||
tailrec open fun foo(x: Int) {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
internal tailrec open fun bar(y: Int) {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
protected tailrec open fun baz(y: Int) {
|
||||
baz(y)
|
||||
}
|
||||
|
||||
private tailrec fun boo(y: Int) {
|
||||
boo(y)
|
||||
}
|
||||
|
||||
internal tailrec fun baa(y: Int) {
|
||||
baa(y)
|
||||
}
|
||||
}
|
||||
|
||||
open class B : A() {
|
||||
final tailrec override fun foo(x: Int) {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
final tailrec override fun bar(y: Int) {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
final tailrec override fun baz(y: Int) {
|
||||
baz(y)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open class C : A() {
|
||||
tailrec override fun foo(x: Int) {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
tailrec override fun bar(y: Int) {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
tailrec override fun baz(y: Int) {
|
||||
baz(y)
|
||||
}
|
||||
}
|
||||
|
||||
object D : A() {
|
||||
tailrec override fun foo(x: Int) {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
tailrec override fun bar(y: Int) {
|
||||
bar(y - 1)
|
||||
}
|
||||
|
||||
tailrec override fun baz(y: Int) {
|
||||
baz(y)
|
||||
}
|
||||
}
|
||||
|
||||
sealed class E : A() {
|
||||
tailrec override fun foo(x: Int) {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
tailrec override fun bar(y: Int) {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
tailrec override fun baz(y: Int) {
|
||||
baz(y)
|
||||
}
|
||||
|
||||
class E1 : E() {
|
||||
tailrec override fun foo(x: Int) {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
tailrec override fun bar(y: Int) {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
tailrec override fun baz(y: Int) {
|
||||
baz(y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class F {
|
||||
F0,
|
||||
F1() {
|
||||
tailrec override fun foo(x: Int) {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
tailrec override fun bar(y: Int) {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
tailrec override fun baz(y: Int) {
|
||||
baz(y)
|
||||
}
|
||||
};
|
||||
|
||||
tailrec open fun foo(x: Int) {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
internal tailrec open fun bar(y: Int) {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
protected tailrec open fun baz(y: Int) {
|
||||
baz(y)
|
||||
}
|
||||
|
||||
private tailrec fun boo(y: Int) {
|
||||
boo(y)
|
||||
}
|
||||
|
||||
internal tailrec fun baa(y: Int) {
|
||||
baa(y)
|
||||
}
|
||||
}
|
||||
|
||||
enum class G {
|
||||
|
||||
G1;
|
||||
|
||||
tailrec open fun foo(x: Int) {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
internal tailrec open fun bar(y: Int) {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
protected tailrec open fun baz(y: Int) {
|
||||
baz(y)
|
||||
}
|
||||
|
||||
private tailrec fun boo(y: Int) {
|
||||
boo(y)
|
||||
}
|
||||
|
||||
internal tailrec fun baa(y: Int) {
|
||||
baa(y)
|
||||
}
|
||||
}
|
||||
|
||||
val z = object : A() {
|
||||
tailrec override fun foo(x: Int) {
|
||||
foo(x)
|
||||
}
|
||||
|
||||
tailrec override fun bar(y: Int) {
|
||||
bar(y)
|
||||
}
|
||||
|
||||
tailrec override fun baz(y: Int) {
|
||||
baz(y)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
//!LANGUAGE: +ProhibitTailrecOnVirtualMember
|
||||
|
||||
open class A {
|
||||
|
||||
@@ -6,12 +6,12 @@ open class A {
|
||||
}
|
||||
|
||||
class B: A() {
|
||||
tailrec override fun foo(x: Int) {
|
||||
foo()
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec override fun foo(x: Int)<!> {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo<!>()
|
||||
}
|
||||
|
||||
tailrec override fun gav(y: Int, z: Int) {
|
||||
gav(y)
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec override fun gav(y: Int, z: Int)<!> {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>gav<!>(y)
|
||||
}
|
||||
|
||||
tailrec fun bar(y: Double): Double = bar(y * 2.0)
|
||||
@@ -29,4 +29,4 @@ class C: A() {
|
||||
tailrec fun bar(y: Int = 1, z: Int = 2) {
|
||||
bar(z)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
object Foo {
|
||||
tailrec fun foo1() {
|
||||
foo1()
|
||||
}
|
||||
|
||||
tailrec fun foo2() {
|
||||
this.foo2()
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo3()<!> {
|
||||
Foo.<!NON_TAIL_RECURSIVE_CALL!>foo3<!>()
|
||||
}
|
||||
}
|
||||
|
||||
class Bar {
|
||||
companion object {
|
||||
tailrec fun bar1() {
|
||||
bar1()
|
||||
}
|
||||
|
||||
tailrec fun bar2() {
|
||||
this.bar2()
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun bar3()<!> {
|
||||
Bar.<!NON_TAIL_RECURSIVE_CALL!>bar3<!>()
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun bar4()<!> {
|
||||
Bar.Companion.<!NON_TAIL_RECURSIVE_CALL!>bar4<!>()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class E {
|
||||
A {
|
||||
override tailrec fun rec() {
|
||||
rec()
|
||||
}
|
||||
},
|
||||
B {
|
||||
override tailrec fun rec() {
|
||||
this.rec()
|
||||
}
|
||||
},
|
||||
C {
|
||||
<!NO_TAIL_CALLS_FOUND!>override tailrec fun rec()<!> {
|
||||
C.rec() // resolution goes to `E.rec`. Hence the resolved symbol is considered different from `C.rec`.
|
||||
}
|
||||
};
|
||||
|
||||
abstract fun rec()
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
object Foo {
|
||||
tailrec fun foo1() {
|
||||
foo1()
|
||||
}
|
||||
|
||||
tailrec fun foo2() {
|
||||
this.foo2()
|
||||
}
|
||||
|
||||
tailrec fun foo3() {
|
||||
Foo.foo3()
|
||||
}
|
||||
}
|
||||
|
||||
class Bar {
|
||||
companion object {
|
||||
tailrec fun bar1() {
|
||||
bar1()
|
||||
}
|
||||
|
||||
tailrec fun bar2() {
|
||||
this.bar2()
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun bar3()<!> {
|
||||
Bar.<!NON_TAIL_RECURSIVE_CALL!>bar3<!>()
|
||||
}
|
||||
|
||||
tailrec fun bar4() {
|
||||
Bar.Companion.bar4()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class E {
|
||||
A {
|
||||
override tailrec fun rec() {
|
||||
rec()
|
||||
}
|
||||
},
|
||||
B {
|
||||
override tailrec fun rec() {
|
||||
this.rec()
|
||||
}
|
||||
},
|
||||
C {
|
||||
<!NO_TAIL_CALLS_FOUND!>override tailrec fun rec()<!> {
|
||||
C.rec() // resolution goes to `E.rec`. Hence the resolved symbol is considered different from `C.rec`.
|
||||
}
|
||||
};
|
||||
|
||||
abstract fun rec()
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package
|
||||
|
||||
public final class Bar {
|
||||
public constructor Bar()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
public companion object Companion {
|
||||
private constructor Companion()
|
||||
public final tailrec fun bar1(): kotlin.Unit
|
||||
public final tailrec fun bar2(): kotlin.Unit
|
||||
public final tailrec fun bar3(): kotlin.Unit
|
||||
public final tailrec fun bar4(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
}
|
||||
|
||||
public final enum class E : kotlin.Enum<E> {
|
||||
enum entry A
|
||||
|
||||
enum entry B
|
||||
|
||||
enum entry C
|
||||
|
||||
private constructor E()
|
||||
public final override /*1*/ /*fake_override*/ val name: kotlin.String
|
||||
public final override /*1*/ /*fake_override*/ val ordinal: kotlin.Int
|
||||
protected final override /*1*/ /*fake_override*/ fun clone(): kotlin.Any
|
||||
public final override /*1*/ /*fake_override*/ fun compareTo(/*0*/ other: E): kotlin.Int
|
||||
public final override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
protected/*protected and package*/ final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun finalize(): kotlin.Unit
|
||||
public final override /*1*/ /*fake_override*/ /*isHiddenForResolutionEverywhereBesideSupercalls*/ fun getDeclaringClass(): java.lang.Class<E!>!
|
||||
public final override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public abstract fun rec(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
|
||||
// Static members
|
||||
public final /*synthesized*/ fun valueOf(/*0*/ value: kotlin.String): E
|
||||
public final /*synthesized*/ fun values(): kotlin.Array<E>
|
||||
}
|
||||
|
||||
public object Foo {
|
||||
private constructor Foo()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final tailrec fun foo1(): kotlin.Unit
|
||||
public final tailrec fun foo2(): kotlin.Unit
|
||||
public final tailrec fun foo3(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// FIR_IDENTICAL
|
||||
class A(val a: A) {
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo1()<!> {
|
||||
a.<!NON_TAIL_RECURSIVE_CALL!>foo1<!>()
|
||||
}
|
||||
|
||||
tailrec fun foo2() {
|
||||
this.foo2()
|
||||
}
|
||||
|
||||
tailrec fun foo3() {
|
||||
foo3()
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo4()<!> {
|
||||
with(a) {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo4<!>()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package
|
||||
|
||||
public final class A {
|
||||
public constructor A(/*0*/ a: A)
|
||||
public final val a: A
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public final tailrec fun foo1(): kotlin.Unit
|
||||
public final tailrec fun foo2(): kotlin.Unit
|
||||
public final tailrec fun foo3(): kotlin.Unit
|
||||
public final tailrec fun foo4(): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// FIR_IDENTICAL
|
||||
tailrec fun String.foo1() {
|
||||
"".foo1()
|
||||
}
|
||||
|
||||
tailrec fun String.foo2() {
|
||||
this.foo2()
|
||||
}
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun String.foo3()<!> {
|
||||
with(this) {
|
||||
<!NON_TAIL_RECURSIVE_CALL!>foo3<!>()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package
|
||||
|
||||
public tailrec fun kotlin.String.foo1(): kotlin.Unit
|
||||
public tailrec fun kotlin.String.foo2(): kotlin.Unit
|
||||
public tailrec fun kotlin.String.foo3(): kotlin.Unit
|
||||
@@ -1,10 +1,10 @@
|
||||
object O {
|
||||
// This is correct, foo is the same
|
||||
tailrec fun foo(i: Int): Int = if (i < 0) 0 else O.foo(i - 1)
|
||||
// foo is the same, but the compiler currently doesn't compile this as tail recursive. See KT-48602
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec fun foo(i: Int): Int<!> = if (i < 0) 0 else O.<!NON_TAIL_RECURSIVE_CALL!>foo<!>(i - 1)
|
||||
}
|
||||
|
||||
class A {
|
||||
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
|
||||
@@ -12,5 +12,5 @@ class A {
|
||||
}
|
||||
|
||||
class B {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
object O {
|
||||
// This is correct, foo is the same
|
||||
// foo is the same, but the compiler currently doesn't compile this as tail recursive. See KT-48602
|
||||
tailrec fun foo(i: Int): Int = if (i < 0) 0 else O.foo(i - 1)
|
||||
}
|
||||
|
||||
|
||||
Generated
+36
@@ -770,6 +770,24 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/SyntaxErrorInTestHighlightingEof.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecBasic.kt")
|
||||
public void testTailRecBasic() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecBasic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecInNestedScopes.kt")
|
||||
public void testTailRecInNestedScopes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecInNestedScopes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecInTry.kt")
|
||||
public void testTailRecInTry() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecInTry.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecOnVirtualMember.kt")
|
||||
public void testTailRecOnVirtualMember() throws Exception {
|
||||
@@ -788,6 +806,24 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecOverridden.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecSingleton.kt")
|
||||
public void testTailRecSingleton() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecSingleton.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecWithDispatchReceiver.kt")
|
||||
public void testTailRecWithDispatchReceiver() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecWithDispatchReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecWithExtensionReceiver.kt")
|
||||
public void testTailRecWithExtensionReceiver() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecWithExtensionReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecursionComplex.kt")
|
||||
public void testTailRecursionComplex() throws Exception {
|
||||
|
||||
+36
@@ -770,6 +770,24 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
runTest("compiler/testData/diagnostics/tests/SyntaxErrorInTestHighlightingEof.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecBasic.kt")
|
||||
public void testTailRecBasic() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecBasic.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecInNestedScopes.kt")
|
||||
public void testTailRecInNestedScopes() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecInNestedScopes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecInTry.kt")
|
||||
public void testTailRecInTry() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecInTry.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecOnVirtualMember.kt")
|
||||
public void testTailRecOnVirtualMember() throws Exception {
|
||||
@@ -788,6 +806,24 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecOverridden.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecSingleton.kt")
|
||||
public void testTailRecSingleton() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecSingleton.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecWithDispatchReceiver.kt")
|
||||
public void testTailRecWithDispatchReceiver() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecWithDispatchReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecWithExtensionReceiver.kt")
|
||||
public void testTailRecWithExtensionReceiver() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/tailRecWithExtensionReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tailRecursionComplex.kt")
|
||||
public void testTailRecursionComplex() throws Exception {
|
||||
|
||||
+25
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.psi.KtImportDirective
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
|
||||
@@ -2169,6 +2170,30 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.NO_TAIL_CALLS_FOUND) { firDiagnostic ->
|
||||
NoTailCallsFoundImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.TAILREC_ON_VIRTUAL_MEMBER_ERROR) { firDiagnostic ->
|
||||
TailrecOnVirtualMemberErrorImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.NON_TAIL_RECURSIVE_CALL) { firDiagnostic ->
|
||||
NonTailRecursiveCallImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED) { firDiagnostic ->
|
||||
TailRecursionInTryIsNotSupportedImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.FUN_INTERFACE_CONSTRUCTOR_REFERENCE) { firDiagnostic ->
|
||||
FunInterfaceConstructorReferenceImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
|
||||
+17
@@ -54,6 +54,7 @@ import org.jetbrains.kotlin.psi.KtImportDirective
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
|
||||
@@ -1542,6 +1543,22 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = CannotInferParameterType::class
|
||||
}
|
||||
|
||||
abstract class NoTailCallsFound : KtFirDiagnostic<KtNamedFunction>() {
|
||||
override val diagnosticClass get() = NoTailCallsFound::class
|
||||
}
|
||||
|
||||
abstract class TailrecOnVirtualMemberError : KtFirDiagnostic<KtNamedFunction>() {
|
||||
override val diagnosticClass get() = TailrecOnVirtualMemberError::class
|
||||
}
|
||||
|
||||
abstract class NonTailRecursiveCall : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = NonTailRecursiveCall::class
|
||||
}
|
||||
|
||||
abstract class TailRecursionInTryIsNotSupported : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = TailRecursionInTryIsNotSupported::class
|
||||
}
|
||||
|
||||
abstract class FunInterfaceConstructorReference : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = FunInterfaceConstructorReference::class
|
||||
}
|
||||
|
||||
+29
@@ -56,6 +56,7 @@ import org.jetbrains.kotlin.psi.KtImportDirective
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
|
||||
@@ -2464,6 +2465,34 @@ internal class CannotInferParameterTypeImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class NoTailCallsFoundImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.NoTailCallsFound(), KtAbstractFirDiagnostic<KtNamedFunction> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class TailrecOnVirtualMemberErrorImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.TailrecOnVirtualMemberError(), KtAbstractFirDiagnostic<KtNamedFunction> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class NonTailRecursiveCallImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.NonTailRecursiveCall(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class TailRecursionInTryIsNotSupportedImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.TailRecursionInTryIsNotSupported(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class FunInterfaceConstructorReferenceImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
|
||||
Reference in New Issue
Block a user