diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index fb85908e14c..612066da86b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2416,7 +2416,7 @@ public class ExpressionCodegen extends KtVisitor impleme ) { boolean isSafeCallOrOnStack = receiver instanceof StackValue.SafeCall || receiver instanceof StackValue.OnStack; - if (isSuspendCall && !isSafeCallOrOnStack) { + if (isSuspendCall && !isSafeCallOrOnStack && !tailRecursionCodegen.isTailRecursion(resolvedCall)) { // Inline markers are used to spill the stack before coroutine suspension addInlineMarker(v, true); } diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowIf.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowIf.kt new file mode 100644 index 00000000000..07e9f23fcf2 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowIf.kt @@ -0,0 +1,41 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* + +class CompilerKillingIterator(private val underlying: Iterator, private val transform: suspend (e: T) -> Iterator) { + private var currentIt: Iterator = object : Iterator { + override fun hasNext() = false + + override fun next(): R = null!! + } + + suspend tailrec fun next(): R { + return if (currentIt.hasNext()) { + currentIt.next() + } else if (underlying.hasNext()) { + currentIt = transform(underlying.next()) + next() + } else { + throw IllegalArgumentException("Cannot call next() on the empty iterator") + } + } + + suspend fun hasNext() = currentIt.hasNext() || underlying.hasNext() +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res = "" + builder { + val iter = CompilerKillingIterator("ok".asIterable().iterator()) { ("" + it.toUpperCase()).asIterable().iterator() } + while (iter.hasNext()) { + res += iter.next() + } + } + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowWhen.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowWhen.kt new file mode 100644 index 00000000000..ade0b26af41 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowWhen.kt @@ -0,0 +1,41 @@ +// WITH_RUNTIME +// WITH_COROUTINES + +import helpers.* +import kotlin.coroutines.experimental.* + +class CompilerKillingIterator(private val underlying: Iterator, private val transform: suspend (e: T) -> Iterator) { + private var currentIt: Iterator = object : Iterator { + override fun hasNext() = false + + override fun next(): R = null!! + } + + suspend tailrec fun next(): R { + return when { + currentIt.hasNext() -> currentIt.next() + underlying.hasNext() -> { + currentIt = transform(underlying.next()) + next() + } + else -> throw IllegalArgumentException("Cannot call next() on the empty iterator") + } + } + + suspend fun hasNext() = currentIt.hasNext() || underlying.hasNext() +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + var res = "" + builder { + val iter = CompilerKillingIterator("ok".asIterable().iterator()) { ("" + it.toUpperCase()).asIterable().iterator() } + while (iter.hasNext()) { + res += iter.next() + } + } + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/extention.kt similarity index 100% rename from compiler/testData/codegen/box/coroutines/featureIntersection/tailrec.kt rename to compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/extention.kt diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixCall.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixCall.kt new file mode 100644 index 00000000000..f0287ad5fb0 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixCall.kt @@ -0,0 +1,25 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// IGNORE_BACKEND_WITHOUT_CHECK: JS + +import helpers.* +import kotlin.coroutines.experimental.* + +tailrec suspend infix fun Int.test(x : Int) : Int { + if (this > 1) { + return (this - 1) test x + } + return this +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box() : String { + var res = "" + builder { + res = if (1000000.test(1000000) == 1) "OK" else "FAIL" + } + return res +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixRecursiveCall.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixRecursiveCall.kt new file mode 100644 index 00000000000..f4088e3a83b --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixRecursiveCall.kt @@ -0,0 +1,23 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// IGNORE_BACKEND_WITHOUT_CHECK: JS + +import helpers.* +import kotlin.coroutines.experimental.* + +tailrec suspend infix fun Int.foo(x: Int) { + if (x == 0) return + val xx = x - 1 + return 1 foo xx +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + builder { + 1 foo 1000000 + } + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realIteratorFoldl.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realIteratorFoldl.kt new file mode 100644 index 00000000000..78b4c3cef5f --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realIteratorFoldl.kt @@ -0,0 +1,24 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// IGNORE_BACKEND_WITHOUT_CHECK: JS +import helpers.* +import kotlin.coroutines.experimental.* + +tailrec suspend fun Iterator.foldl(acc : A, foldFunction : (e : T, acc : A) -> A) : A = + if (!hasNext()) acc + else foldl(foldFunction(next(), acc), foldFunction) + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box() : String { + var sum = 0L + builder { + sum = (1..1000000).iterator().foldl(0) { e : Int, acc : Long -> + acc + e + } + } + + return if (sum == 500000500000) "OK" else "FAIL: $sum" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringEscape.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringEscape.kt new file mode 100644 index 00000000000..0b168f575c6 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringEscape.kt @@ -0,0 +1,27 @@ +// WITH_RUNTIME +// WITH_COROUTINES +import helpers.* +import kotlin.coroutines.experimental.* + +suspend fun escapeChar(c : Char) : String? = when (c) { + '\\' -> "\\\\" + '\n' -> "\\n" + '"' -> "\\\"" + else -> "" + c +} + +tailrec suspend fun String.escape(i : Int = 0, result : StringBuilder = StringBuilder()) : String = + if (i == length) result.toString() + else escape(i + 1, result.append(escapeChar(get(i)))) + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box() : String { + var res = "" + builder { + res = "test me not \\".escape() + } + return if (res == "test me not \\\\") "OK" else res +} diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringRepeat.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringRepeat.kt new file mode 100644 index 00000000000..2f934d73d95 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringRepeat.kt @@ -0,0 +1,21 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// IGNORE_BACKEND_WITHOUT_CHECK: JS +import helpers.* +import kotlin.coroutines.experimental.* + +tailrec suspend fun String.repeat(num : Int, acc : StringBuilder = StringBuilder()) : String = + if (num == 0) acc.toString() + else repeat(num - 1, acc.append(this)) + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box() : String { + var s: String = "" + builder { + s = "a".repeat(10000) + } + return if (s.length == 10000) "OK" else "FAIL: ${s.length}" +} diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/returnInParentheses.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/returnInParentheses.kt new file mode 100644 index 00000000000..27c6d86c079 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/returnInParentheses.kt @@ -0,0 +1,21 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// IGNORE_BACKEND_WITHOUT_CHECK: JS +import helpers.* +import kotlin.coroutines.experimental.* + +tailrec suspend fun foo(x: Int) { + if (x == 0) return + (return foo(x - 1)) +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + builder { + foo(1000000) + } + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/sum.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/sum.kt new file mode 100644 index 00000000000..411725bd761 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/sum.kt @@ -0,0 +1,23 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// IGNORE_BACKEND_WITHOUT_CHECK: JS +import helpers.* +import kotlin.coroutines.experimental.* + +tailrec suspend fun sum(x: Long, sum: Long): Long { + if (x == 0.toLong()) return sum + return sum(x - 1, sum + x) +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box() : String { + var sum: Long = 0L + builder { + sum = sum(1000000, 0) + } + if (sum != 500000500000.toLong()) return "Fail $sum" + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInBlockInParentheses.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInBlockInParentheses.kt new file mode 100644 index 00000000000..bcb60f468f5 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInBlockInParentheses.kt @@ -0,0 +1,23 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// IGNORE_BACKEND_WITHOUT_CHECK: JS +import helpers.* +import kotlin.coroutines.experimental.* + +tailrec suspend fun foo(x: Int) { + return if (x > 0) { + (foo(x - 1)) + } + else Unit +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + builder { + foo(1000000) + } + return "OK" +} diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInParentheses.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInParentheses.kt new file mode 100644 index 00000000000..ccbf0fb9b94 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInParentheses.kt @@ -0,0 +1,21 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// IGNORE_BACKEND_WITHOUT_CHECK: JS +import helpers.* +import kotlin.coroutines.experimental.* + +tailrec suspend fun foo(x: Int) { + if (x == 0) return + return (foo(x - 1)) +} + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box(): String { + builder { + foo(1000000) + } + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/whenWithIs.kt b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/whenWithIs.kt new file mode 100644 index 00000000000..d7e99c21f6a --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/whenWithIs.kt @@ -0,0 +1,31 @@ +// WITH_RUNTIME +// WITH_COROUTINES +// IGNORE_BACKEND_WITHOUT_CHECK: JS +import helpers.* +import kotlin.coroutines.experimental.* + +tailrec suspend fun withWhen(counter : Int, d : Any) : Int = + if (counter == 0) { + 0 + } + else if (counter == 5) { + withWhen(counter - 1, 999) + } + else + when (d) { + is String -> withWhen(counter - 1, "is String") + is Number -> withWhen(counter, "is Number") + else -> throw IllegalStateException() + } + +fun builder(c: suspend () -> Unit) { + c.startCoroutine(EmptyContinuation) +} + +fun box() : String { + var res = -1 + builder { + res = withWhen(100000, "test") + } + return if (res == 0) "OK" else "FAIL" +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 6855b264b92..7974060704a 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -6325,10 +6325,91 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } - @TestMetadata("tailrec.kt") - public void testTailrec() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec.kt"); - doTest(fileName); + @TestMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Tailrec extends AbstractIrBlackBoxCodegenTest { + public void testAllFilesPresentInTailrec() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("controlFlowIf.kt") + public void testControlFlowIf() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowIf.kt"); + doTest(fileName); + } + + @TestMetadata("controlFlowWhen.kt") + public void testControlFlowWhen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowWhen.kt"); + doTest(fileName); + } + + @TestMetadata("extention.kt") + public void testExtention() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/extention.kt"); + doTest(fileName); + } + + @TestMetadata("infixCall.kt") + public void testInfixCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixCall.kt"); + doTest(fileName); + } + + @TestMetadata("infixRecursiveCall.kt") + public void testInfixRecursiveCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixRecursiveCall.kt"); + doTest(fileName); + } + + @TestMetadata("realIteratorFoldl.kt") + public void testRealIteratorFoldl() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realIteratorFoldl.kt"); + doTest(fileName); + } + + @TestMetadata("realStringEscape.kt") + public void testRealStringEscape() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringEscape.kt"); + doTest(fileName); + } + + @TestMetadata("realStringRepeat.kt") + public void testRealStringRepeat() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringRepeat.kt"); + doTest(fileName); + } + + @TestMetadata("returnInParentheses.kt") + public void testReturnInParentheses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/returnInParentheses.kt"); + doTest(fileName); + } + + @TestMetadata("sum.kt") + public void testSum() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/sum.kt"); + doTest(fileName); + } + + @TestMetadata("tailCallInBlockInParentheses.kt") + public void testTailCallInBlockInParentheses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInBlockInParentheses.kt"); + doTest(fileName); + } + + @TestMetadata("tailCallInParentheses.kt") + public void testTailCallInParentheses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInParentheses.kt"); + doTest(fileName); + } + + @TestMetadata("whenWithIs.kt") + public void testWhenWithIs() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/whenWithIs.kt"); + doTest(fileName); + } } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 1656e2d424e..4c8649a1172 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -6325,10 +6325,91 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } - @TestMetadata("tailrec.kt") - public void testTailrec() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec.kt"); - doTest(fileName); + @TestMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Tailrec extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInTailrec() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("controlFlowIf.kt") + public void testControlFlowIf() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowIf.kt"); + doTest(fileName); + } + + @TestMetadata("controlFlowWhen.kt") + public void testControlFlowWhen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowWhen.kt"); + doTest(fileName); + } + + @TestMetadata("extention.kt") + public void testExtention() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/extention.kt"); + doTest(fileName); + } + + @TestMetadata("infixCall.kt") + public void testInfixCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixCall.kt"); + doTest(fileName); + } + + @TestMetadata("infixRecursiveCall.kt") + public void testInfixRecursiveCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixRecursiveCall.kt"); + doTest(fileName); + } + + @TestMetadata("realIteratorFoldl.kt") + public void testRealIteratorFoldl() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realIteratorFoldl.kt"); + doTest(fileName); + } + + @TestMetadata("realStringEscape.kt") + public void testRealStringEscape() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringEscape.kt"); + doTest(fileName); + } + + @TestMetadata("realStringRepeat.kt") + public void testRealStringRepeat() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringRepeat.kt"); + doTest(fileName); + } + + @TestMetadata("returnInParentheses.kt") + public void testReturnInParentheses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/returnInParentheses.kt"); + doTest(fileName); + } + + @TestMetadata("sum.kt") + public void testSum() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/sum.kt"); + doTest(fileName); + } + + @TestMetadata("tailCallInBlockInParentheses.kt") + public void testTailCallInBlockInParentheses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInBlockInParentheses.kt"); + doTest(fileName); + } + + @TestMetadata("tailCallInParentheses.kt") + public void testTailCallInParentheses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInParentheses.kt"); + doTest(fileName); + } + + @TestMetadata("whenWithIs.kt") + public void testWhenWithIs() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/whenWithIs.kt"); + doTest(fileName); + } } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 4244bf6adb4..aedfbdac1b7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -6325,10 +6325,91 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes doTest(fileName); } - @TestMetadata("tailrec.kt") - public void testTailrec() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec.kt"); - doTest(fileName); + @TestMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Tailrec extends AbstractLightAnalysisModeTest { + public void testAllFilesPresentInTailrec() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); + } + + @TestMetadata("controlFlowIf.kt") + public void testControlFlowIf() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowIf.kt"); + doTest(fileName); + } + + @TestMetadata("controlFlowWhen.kt") + public void testControlFlowWhen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowWhen.kt"); + doTest(fileName); + } + + @TestMetadata("extention.kt") + public void testExtention() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/extention.kt"); + doTest(fileName); + } + + @TestMetadata("infixCall.kt") + public void testInfixCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixCall.kt"); + doTest(fileName); + } + + @TestMetadata("infixRecursiveCall.kt") + public void testInfixRecursiveCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixRecursiveCall.kt"); + doTest(fileName); + } + + @TestMetadata("realIteratorFoldl.kt") + public void testRealIteratorFoldl() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realIteratorFoldl.kt"); + doTest(fileName); + } + + @TestMetadata("realStringEscape.kt") + public void testRealStringEscape() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringEscape.kt"); + doTest(fileName); + } + + @TestMetadata("realStringRepeat.kt") + public void testRealStringRepeat() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringRepeat.kt"); + doTest(fileName); + } + + @TestMetadata("returnInParentheses.kt") + public void testReturnInParentheses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/returnInParentheses.kt"); + doTest(fileName); + } + + @TestMetadata("sum.kt") + public void testSum() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/sum.kt"); + doTest(fileName); + } + + @TestMetadata("tailCallInBlockInParentheses.kt") + public void testTailCallInBlockInParentheses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInBlockInParentheses.kt"); + doTest(fileName); + } + + @TestMetadata("tailCallInParentheses.kt") + public void testTailCallInParentheses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInParentheses.kt"); + doTest(fileName); + } + + @TestMetadata("whenWithIs.kt") + public void testWhenWithIs() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/whenWithIs.kt"); + doTest(fileName); + } } } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 47bbe38e1d1..6f3ae6da31f 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -7644,10 +7644,91 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { doTest(fileName); } - @TestMetadata("tailrec.kt") - public void testTailrec() throws Exception { - String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec.kt"); - doTest(fileName); + @TestMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Tailrec extends AbstractJsCodegenBoxTest { + @TestMetadata("infixCall.kt") + public void ignoreInfixCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixCall.kt"); + doTest(fileName); + } + + @TestMetadata("infixRecursiveCall.kt") + public void ignoreInfixRecursiveCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/infixRecursiveCall.kt"); + doTest(fileName); + } + + @TestMetadata("realIteratorFoldl.kt") + public void ignoreRealIteratorFoldl() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realIteratorFoldl.kt"); + doTest(fileName); + } + + @TestMetadata("realStringRepeat.kt") + public void ignoreRealStringRepeat() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringRepeat.kt"); + doTest(fileName); + } + + @TestMetadata("returnInParentheses.kt") + public void ignoreReturnInParentheses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/returnInParentheses.kt"); + doTest(fileName); + } + + @TestMetadata("sum.kt") + public void ignoreSum() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/sum.kt"); + doTest(fileName); + } + + @TestMetadata("tailCallInBlockInParentheses.kt") + public void ignoreTailCallInBlockInParentheses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInBlockInParentheses.kt"); + doTest(fileName); + } + + @TestMetadata("tailCallInParentheses.kt") + public void ignoreTailCallInParentheses() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/tailCallInParentheses.kt"); + doTest(fileName); + } + + @TestMetadata("whenWithIs.kt") + public void ignoreWhenWithIs() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/whenWithIs.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInTailrec() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true); + } + + @TestMetadata("controlFlowIf.kt") + public void testControlFlowIf() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowIf.kt"); + doTest(fileName); + } + + @TestMetadata("controlFlowWhen.kt") + public void testControlFlowWhen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/controlFlowWhen.kt"); + doTest(fileName); + } + + @TestMetadata("extention.kt") + public void testExtention() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/extention.kt"); + doTest(fileName); + } + + @TestMetadata("realStringEscape.kt") + public void testRealStringEscape() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/featureIntersection/tailrec/realStringEscape.kt"); + doTest(fileName); + } } }