Indirect tests for tail call diagnostics removed
This commit is contained in:
@@ -1,12 +1,10 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
tailRecursive fun test(counter : Int) : Int? {
|
||||||
|
|
||||||
tailRecursive fun test(counter : Int, a : Any) : Int? {
|
|
||||||
if (counter < 0) return null
|
if (counter < 0) return null
|
||||||
if (counter == 0) return 777
|
if (counter == 0) return 777
|
||||||
|
|
||||||
return <!NON_TAIL_RECURSIVE_CALL!>test<!>(-1, "no tail") ?: <!NON_TAIL_RECURSIVE_CALL!>test<!>(-2, "no tail") ?: test(counter - 1, "tail")
|
return <!NON_TAIL_RECURSIVE_CALL!>test<!>(-1) ?: <!NON_TAIL_RECURSIVE_CALL!>test<!>(-2) ?: test(counter - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String =
|
fun box() : String =
|
||||||
if (test(100000, "test") == 777) "OK"
|
if (test(100000) == 777) "OK"
|
||||||
else "FAIL"
|
else "FAIL"
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
class B {
|
class B {
|
||||||
inner class C {
|
inner class C {
|
||||||
tailRecursive fun h(counter : Int, x : Any) {
|
tailRecursive fun h(counter : Int) {
|
||||||
if (counter > 0) {
|
if (counter > 0) {
|
||||||
this@C.h(counter - 1, "tail")
|
this@C.h(counter - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ class B {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String {
|
fun box() : String {
|
||||||
B().makeC().h(1000000, "test")
|
B().makeC().h(1000000)
|
||||||
B().makeC().h2(0)
|
B().makeC().h2(0)
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
tailRecursive fun test(x : Int) : Int {
|
||||||
|
|
||||||
tailRecursive fun test(x : Int, a : Any) : Int {
|
|
||||||
var z = if (x > 3) 3 else x
|
var z = if (x > 3) 3 else x
|
||||||
while (z > 0) {
|
while (z > 0) {
|
||||||
if (z > 10) {
|
if (z > 10) {
|
||||||
return test(x - 1, "tail")
|
return test(x - 1)
|
||||||
}
|
}
|
||||||
<!NON_TAIL_RECURSIVE_CALL!>test<!>(0, "no tail")
|
<!NON_TAIL_RECURSIVE_CALL!>test<!>(0)
|
||||||
z = z - 1
|
z = z - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String = if (test(100000, "test") == 1) "OK" else "FAIL"
|
fun box() : String = if (test(100000) == 1) "OK" else "FAIL"
|
||||||
@@ -1,17 +1,15 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
tailRecursive fun test(x : Int) : Int {
|
||||||
|
|
||||||
tailRecursive fun test(x : Int, a : Any) : Int {
|
|
||||||
if (x == 1) {
|
if (x == 1) {
|
||||||
if (x != 1) {
|
if (x != 1) {
|
||||||
<!NON_TAIL_RECURSIVE_CALL!>test<!>(0, "no tail")
|
<!NON_TAIL_RECURSIVE_CALL!>test<!>(0)
|
||||||
return test(0, "tail")
|
return test(0)
|
||||||
} else {
|
} else {
|
||||||
return test(x + <!NON_TAIL_RECURSIVE_CALL!>test<!>(0, "no tail"), "tail")
|
return test(x + <!NON_TAIL_RECURSIVE_CALL!>test<!>(0))
|
||||||
}
|
}
|
||||||
} else if (x > 0) {
|
} else if (x > 0) {
|
||||||
return test(x - 1, "tail")
|
return test(x - 1)
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String = if (test(1000000, "test") == -1) "OK" else "FAIL"
|
fun box() : String = if (test(1000000) == -1) "OK" else "FAIL"
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
[tailRecursive] fun g3(counter : Int, x : Any) {
|
[tailRecursive] fun g3(counter : Int) {
|
||||||
if (counter > 0) { g3(counter - 1, "tail") }
|
if (counter > 0) { g3(counter - 1) }
|
||||||
}
|
}
|
||||||
g3(1000000, "test")
|
g3(1000000)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String {
|
fun box() : String {
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
<!NO_TAIL_CALLS_FOUND!>tailRecursive fun test(counter : Int) : Int<!> {
|
||||||
|
|
||||||
<!NO_TAIL_CALLS_FOUND!>tailRecursive fun test(counter : Int, a : Any) : Int<!> {
|
|
||||||
if (counter == 0) return 0
|
if (counter == 0) return 0
|
||||||
|
|
||||||
try {
|
try {
|
||||||
throw Exception()
|
throw Exception()
|
||||||
} catch (e : Exception) {
|
} catch (e : Exception) {
|
||||||
return <!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>test<!>(counter - 1, "no tail")
|
return <!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>test<!>(counter - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String = if (test(3, "test") == 0) "OK" else "FAIL"
|
fun box() : String = if (test(3) == 0) "OK" else "FAIL"
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
<!NO_TAIL_CALLS_FOUND!>tailRecursive fun test(counter : Int) : Int<!> {
|
||||||
|
|
||||||
<!NO_TAIL_CALLS_FOUND!>tailRecursive fun test(counter : Int, a : Any) : Int<!> {
|
|
||||||
if (counter == 0) return 0
|
if (counter == 0) return 0
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// do nothing
|
// do nothing
|
||||||
} finally {
|
} finally {
|
||||||
return <!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>test<!>(counter - 1, "no tail")
|
return <!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>test<!>(counter - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String = if (test(3, "test") == 0) "OK" else "FAIL"
|
fun box() : String = if (test(3) == 0) "OK" else "FAIL"
|
||||||
@@ -1,17 +1,15 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
<!NO_TAIL_CALLS_FOUND!>tailRecursive fun test(counter : Int) : Int<!> {
|
||||||
|
|
||||||
<!NO_TAIL_CALLS_FOUND!>tailRecursive fun test(counter : Int, a : Any) : Int<!> {
|
|
||||||
if (counter == 0) return 0
|
if (counter == 0) return 0
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// do nothing
|
// do nothing
|
||||||
} finally {
|
} finally {
|
||||||
if (counter > 0) {
|
if (counter > 0) {
|
||||||
return <!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>test<!>(counter - 1, "no tail")
|
return <!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>test<!>(counter - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String = if (test(3, "test") == 0) "OK" else "FAIL"
|
fun box() : String = if (test(3) == 0) "OK" else "FAIL"
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
<!NO_TAIL_CALLS_FOUND!>tailRecursive fun test(counter : Int) : Int<!> {
|
||||||
|
|
||||||
<!NO_TAIL_CALLS_FOUND!>tailRecursive fun test(counter : Int, a : Any) : Int<!> {
|
|
||||||
if (counter == 0) return 0
|
if (counter == 0) return 0
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return <!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>test<!>(counter - 1, "no tail")
|
return <!TAIL_RECURSION_IN_TRY_IS_NOT_SUPPORTED!>test<!>(counter - 1)
|
||||||
} catch (any : Throwable) {
|
} catch (any : Throwable) {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String = if (test(3, "test") == 0) "OK" else "FAIL"
|
fun box() : String = if (test(3) == 0) "OK" else "FAIL"
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
tailRecursive fun test(x : Int) : Int =
|
||||||
|
|
||||||
tailRecursive fun test(x : Int, a : Any) : Int =
|
|
||||||
if (x == 1) {
|
if (x == 1) {
|
||||||
<!NON_TAIL_RECURSIVE_CALL!>test<!>(x - 1, "no tail")
|
<!NON_TAIL_RECURSIVE_CALL!>test<!>(x - 1)
|
||||||
1 + <!NON_TAIL_RECURSIVE_CALL!>test<!>(x - 1, "no tail")
|
1 + <!NON_TAIL_RECURSIVE_CALL!>test<!>(x - 1)
|
||||||
} else if (x > 0) {
|
} else if (x > 0) {
|
||||||
test(x - 1, "tail")
|
test(x - 1)
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String = if (test(1000000, "test") == 1) "OK" else "FAIL"
|
fun box() : String = if (test(1000000) == 1) "OK" else "FAIL"
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
tailRecursive fun test(x : Int) : Int {
|
||||||
|
|
||||||
tailRecursive fun test(x : Int, z : Any) : Int {
|
|
||||||
if (x == 10) {
|
if (x == 10) {
|
||||||
return 1 + <!NON_TAIL_RECURSIVE_CALL!>test<!>(x - 1, "no tail")
|
return 1 + <!NON_TAIL_RECURSIVE_CALL!>test<!>(x - 1)
|
||||||
}
|
}
|
||||||
if (x > 0) {
|
if (x > 0) {
|
||||||
return test(x - 1, "tail")
|
return test(x - 1)
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String = if (test(1000000, "test") == 1) "OK" else "FAIL"
|
fun box() : String = if (test(1000000) == 1) "OK" else "FAIL"
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
tailRecursive fun test(x : Int) : Int {
|
||||||
|
|
||||||
tailRecursive fun test(x : Int, a : Any) : Int {
|
|
||||||
if (x == 0) {
|
if (x == 0) {
|
||||||
return 0
|
return 0
|
||||||
} else if (x == 10) {
|
} else if (x == 10) {
|
||||||
<!NON_TAIL_RECURSIVE_CALL!>test<!>(0, "no tail")
|
<!NON_TAIL_RECURSIVE_CALL!>test<!>(0)
|
||||||
return 1 + <!NON_TAIL_RECURSIVE_CALL!>test<!>(x - 1, "no tail")
|
return 1 + <!NON_TAIL_RECURSIVE_CALL!>test<!>(x - 1)
|
||||||
} else {
|
} else {
|
||||||
return test(x - 1, "tail")
|
return test(x - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String = if (test(1000000, "test") == 1) "OK" else "FAIL"
|
fun box() : String = if (test(1000000) == 1) "OK" else "FAIL"
|
||||||
@@ -1,25 +1,23 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
|
||||||
|
|
||||||
class A {
|
class A {
|
||||||
tailRecursive fun f1(c : Int, x : Any) {
|
tailRecursive fun f1(c : Int) {
|
||||||
if (c > 0) {
|
if (c > 0) {
|
||||||
this.f1(c - 1, "tail")
|
this.f1(c - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tailRecursive fun f2(c : Int, x : Any) {
|
tailRecursive fun f2(c : Int) {
|
||||||
if (c > 0) {
|
if (c > 0) {
|
||||||
f2(c - 1, "tail 108")
|
f2(c - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<!NO_TAIL_CALLS_FOUND!>tailRecursive fun f3(a : A, x : Any)<!> {
|
<!NO_TAIL_CALLS_FOUND!>tailRecursive fun f3(a : A)<!> {
|
||||||
a.<!NON_TAIL_RECURSIVE_CALL!>f3<!>(a, "no tail") // non-tail recursion, could be potentially resolved by condition if (a == this) f3() else a.f3()
|
a.<!NON_TAIL_RECURSIVE_CALL!>f3<!>(a) // non-tail recursion, could be potentially resolved by condition if (a == this) f3() else a.f3()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String {
|
fun box() : String {
|
||||||
A().f1(1000000, "test")
|
A().f1(1000000)
|
||||||
A().f2(1000000, "test")
|
A().f2(1000000)
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,21 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
tailRecursive fun test(x : Int) : Unit {
|
||||||
|
|
||||||
tailRecursive fun test(x : Int, e : Any) : Unit {
|
|
||||||
if (x == 1) {
|
if (x == 1) {
|
||||||
test(x - 1, "tail")
|
test(x - 1)
|
||||||
} else if (x == 2) {
|
} else if (x == 2) {
|
||||||
test(x - 1, "tail")
|
test(x - 1)
|
||||||
return
|
return
|
||||||
} else if (x == 3) {
|
} else if (x == 3) {
|
||||||
<!NON_TAIL_RECURSIVE_CALL!>test<!>(x - 1, "no tail")
|
<!NON_TAIL_RECURSIVE_CALL!>test<!>(x - 1)
|
||||||
if (x == 3) {
|
if (x == 3) {
|
||||||
test(x - 1, "tail")
|
test(x - 1)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
} else if (x > 0) {
|
} else if (x > 0) {
|
||||||
test(x - 1, "tail")
|
test(x - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String {
|
fun box() : String {
|
||||||
test(1000000, "test")
|
test(1000000)
|
||||||
return "OK"
|
return "OK"
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
tailRecursive fun withWhen(counter : Int) : Int =
|
||||||
|
|
||||||
tailRecursive fun withWhen(counter : Int, x : Any) : Int =
|
|
||||||
when (counter) {
|
when (counter) {
|
||||||
0 -> counter
|
0 -> counter
|
||||||
50 -> 1 + <!NON_TAIL_RECURSIVE_CALL!>withWhen<!>(counter - 1, "no tail")
|
50 -> 1 + <!NON_TAIL_RECURSIVE_CALL!>withWhen<!>(counter - 1)
|
||||||
else -> withWhen(counter - 1, "tail")
|
else -> withWhen(counter - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String = if (withWhen(100000, "test") == 1) "OK" else "FAIL"
|
fun box() : String = if (withWhen(100000) == 1) "OK" else "FAIL"
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
tailRecursive fun withWhen(counter : Int, d : Any, x : Any) : Int =
|
tailRecursive fun withWhen(counter : Int, d : Any) : Int =
|
||||||
when (counter) {
|
when (counter) {
|
||||||
0 -> counter
|
0 -> counter
|
||||||
1, 2 -> withWhen(counter - 1, "1,2", "tail")
|
1, 2 -> withWhen(counter - 1, "1,2")
|
||||||
in 3..49 -> withWhen(counter - 1, "3..49", "tail")
|
in 3..49 -> withWhen(counter - 1, "3..49")
|
||||||
50 -> 1 + <!NON_TAIL_RECURSIVE_CALL!>withWhen<!>(counter - 1, "50", "no tail")
|
50 -> 1 + <!NON_TAIL_RECURSIVE_CALL!>withWhen<!>(counter - 1, "50")
|
||||||
!in 0..50 -> withWhen(counter - 1, "!0..50", "tail")
|
!in 0..50 -> withWhen(counter - 1, "!0..50")
|
||||||
else -> withWhen(counter - 1, "else", "tail")
|
else -> withWhen(counter - 1, "else")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String = if (withWhen(100000, "test", "test") == 1) "OK" else "FAIL"
|
fun box() : String = if (withWhen(100000, "test") == 1) "OK" else "FAIL"
|
||||||
@@ -1,17 +1,15 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
tailRecursive fun withWhen(counter : Int, d : Any) : Int =
|
||||||
|
|
||||||
tailRecursive fun withWhen(counter : Int, d : Any, x : Any) : Int =
|
|
||||||
if (counter == 0) {
|
if (counter == 0) {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
else if (counter == 5) {
|
else if (counter == 5) {
|
||||||
withWhen(counter - 1, 999, "tail")
|
withWhen(counter - 1, 999)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
when (d) {
|
when (d) {
|
||||||
is String -> withWhen(counter - 1, "is String", "tail")
|
is String -> withWhen(counter - 1, "is String")
|
||||||
is Number -> withWhen(counter, "is Number", "tail")
|
is Number -> withWhen(counter, "is Number")
|
||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String = if (withWhen(100000, "test", "test") == 0) "OK" else "FAIL"
|
fun box() : String = if (withWhen(100000, "test") == 0) "OK" else "FAIL"
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
tailRecursive fun withWhen2(counter : Int) : Int =
|
||||||
|
|
||||||
tailRecursive fun withWhen2(counter : Int, x : Any) : Int =
|
|
||||||
when {
|
when {
|
||||||
counter == 0 -> counter
|
counter == 0 -> counter
|
||||||
counter == 50 -> 1 + <!NON_TAIL_RECURSIVE_CALL!>withWhen2<!>(counter - 1, "no tail")
|
counter == 50 -> 1 + <!NON_TAIL_RECURSIVE_CALL!>withWhen2<!>(counter - 1)
|
||||||
<!NON_TAIL_RECURSIVE_CALL!>withWhen2<!>(0, "no tail") == 0 -> withWhen2(counter - 1, "tail")
|
<!NON_TAIL_RECURSIVE_CALL!>withWhen2<!>(0) == 0 -> withWhen2(counter - 1)
|
||||||
else -> 1
|
else -> 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fun box() : String = if (withWhen2(100000, "test") == 1) "OK" else "FAIL"
|
fun box() : String = if (withWhen2(100000) == 1) "OK" else "FAIL"
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2013 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.jet.checkers;
|
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
|
||||||
import com.google.common.base.Joiner;
|
|
||||||
import com.google.common.base.Predicates;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.intellij.openapi.util.io.FileUtil;
|
|
||||||
import com.intellij.psi.PsiFile;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.jet.ConfigurationKind;
|
|
||||||
import org.jetbrains.jet.cli.jvm.compiler.CliLightClassGenerationSupport;
|
|
||||||
import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment;
|
|
||||||
import org.jetbrains.jet.lang.resolve.calls.TailRecursionKind;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor;
|
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
|
||||||
import org.jetbrains.jet.lang.resolve.AnalyzerScriptParameter;
|
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
|
||||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
|
||||||
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
|
|
||||||
import org.jetbrains.jet.lang.resolve.lazy.KotlinTestWithEnvironment;
|
|
||||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public abstract class AbstractTailRecursionTest extends KotlinTestWithEnvironment {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected JetCoreEnvironment createEnvironment() {
|
|
||||||
return createEnvironmentWithMockJdk(ConfigurationKind.JDK_AND_ANNOTATIONS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void doTest(@NotNull String testFile) throws IOException {
|
|
||||||
JetFile file = JetPsiFactory.createFile(getProject(), FileUtil.loadFile(new File(testFile), true));
|
|
||||||
List<JetFile> files = new ArrayList<JetFile>(Collections.singleton(file));
|
|
||||||
|
|
||||||
final BindingTrace trace = CliLightClassGenerationSupport.getInstanceForCli(getProject()).getTrace();
|
|
||||||
assertNotNull("No binding trace found for test", trace);
|
|
||||||
|
|
||||||
AnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
|
|
||||||
getProject(), files, trace,
|
|
||||||
Collections.<AnalyzerScriptParameter>emptyList(), Predicates.<PsiFile>alwaysTrue(), false).getBindingContext();
|
|
||||||
|
|
||||||
file.acceptChildren(new JetTreeVisitor<Data>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitNamedFunction(@NotNull JetNamedFunction function, @Nullable Data outerData) {
|
|
||||||
SimpleFunctionDescriptor descriptor = trace.get(BindingContext.FUNCTION, function);
|
|
||||||
assert descriptor != null : "can't get function descriptor from binding by function declaration node";
|
|
||||||
|
|
||||||
Data data = new Data(descriptor);
|
|
||||||
super.visitNamedFunction(function, data);
|
|
||||||
|
|
||||||
if (data.isTail) {
|
|
||||||
List<JetCallExpression> calls = trace.get(BindingContext.FUNCTION_RECURSIVE_CALL_EXPRESSIONS, descriptor);
|
|
||||||
if (calls == null) {
|
|
||||||
calls = Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<JetCallExpression> detectedRecursions = new ArrayList<JetCallExpression>(calls);
|
|
||||||
List<JetCallExpression> expectedRecursions = new ArrayList<JetCallExpression>(data.visitedCalls);
|
|
||||||
|
|
||||||
Collections.sort(detectedRecursions, new CallComparator());
|
|
||||||
Collections.sort(expectedRecursions, new CallComparator());
|
|
||||||
|
|
||||||
assertEquals(
|
|
||||||
"Bad detected tail recursions list for " + descriptor,
|
|
||||||
stringListOfCallExpressions(expectedRecursions),
|
|
||||||
stringListOfCallExpressions(detectedRecursions)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void visitCallExpression(@NotNull JetCallExpression expression, @Nullable Data data) {
|
|
||||||
if (data != null && data.isTail) {
|
|
||||||
ResolvedCall<? extends CallableDescriptor> call =
|
|
||||||
trace.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression());
|
|
||||||
|
|
||||||
assert call != null : "call node is not yet resolved";
|
|
||||||
if (data.functionDescriptor.equals(call.getCandidateDescriptor())) {
|
|
||||||
JetValueArgumentList argumentList = expression.getValueArgumentList();
|
|
||||||
assert argumentList != null : "function call have no arguments list";
|
|
||||||
|
|
||||||
checkCall(data.functionDescriptor, expression, argumentList, trace);
|
|
||||||
data.visitedCalls.add(expression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.visitCallExpression(expression, data);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String stringListOfCallExpressions(List<JetCallExpression> expectedRecursions) {
|
|
||||||
return Joiner.on(",\n").skipNulls().join(Lists.transform(expectedRecursions, new CallExpressionToText()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Data {
|
|
||||||
public final SimpleFunctionDescriptor functionDescriptor;
|
|
||||||
public final boolean isTail;
|
|
||||||
public final List<JetCallExpression> visitedCalls = new ArrayList<JetCallExpression>();
|
|
||||||
|
|
||||||
private Data(@NotNull SimpleFunctionDescriptor descriptor) {
|
|
||||||
functionDescriptor = descriptor;
|
|
||||||
isTail = KotlinBuiltIns.getInstance().isTailRecursive(descriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void checkCall(
|
|
||||||
SimpleFunctionDescriptor functionDescriptor,
|
|
||||||
JetCallExpression expression,
|
|
||||||
JetValueArgumentList argumentList,
|
|
||||||
BindingTrace trace
|
|
||||||
) {
|
|
||||||
int size = argumentList.getArguments().size();
|
|
||||||
boolean shouldBeTail = size == 0 || isLastArgumentTail(argumentList.getArguments());
|
|
||||||
TailRecursionKind status = trace.get(BindingContext.TAIL_RECURSION_CALL, expression);
|
|
||||||
assertNotNull("Call is not checked for tail recursion", status);
|
|
||||||
assertEquals("Tail-recursion detection failed for " + functionDescriptor.getName().asString() + " at " + expression.getText(),
|
|
||||||
shouldBeTail, status.isDoGenerateTailRecursion());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isLastArgumentTail(List<JetValueArgument> arguments) {
|
|
||||||
JetValueArgument lastArgument = arguments.get(arguments.size() - 1);
|
|
||||||
JetExpression expression = lastArgument.getArgumentExpression();
|
|
||||||
if (expression instanceof JetStringTemplateExpression) {
|
|
||||||
JetStringTemplateEntry[] entries = ((JetStringTemplateExpression) expression).getEntries();
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (JetStringTemplateEntry entry : entries) {
|
|
||||||
sb.append(entry.getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
return !sb.toString().trim().equals("no tail");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class CallComparator implements Comparator<JetCallExpression> {
|
|
||||||
@Override
|
|
||||||
public int compare(@NotNull JetCallExpression o1, @NotNull JetCallExpression o2) {
|
|
||||||
return o1.getTextOffset() - o2.getTextOffset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class CallExpressionToText implements Function<JetCallExpression, String> {
|
|
||||||
@Override
|
|
||||||
public String apply(JetCallExpression input) {
|
|
||||||
if (input == null) return null;
|
|
||||||
return ("\"" + input.getText().replace("\"", "\\\"").trim() + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2013 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.jet.checkers;
|
|
||||||
|
|
||||||
import junit.framework.Assert;
|
|
||||||
import junit.framework.Test;
|
|
||||||
import junit.framework.TestSuite;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import org.jetbrains.jet.JetTestUtils;
|
|
||||||
import org.jetbrains.jet.test.InnerTestClasses;
|
|
||||||
import org.jetbrains.jet.test.TestMetadata;
|
|
||||||
|
|
||||||
import org.jetbrains.jet.checkers.AbstractTailRecursionTest;
|
|
||||||
|
|
||||||
/** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/functions/tailRecursion")
|
|
||||||
public class TailRecursionDetectorTestGenerated extends AbstractTailRecursionTest {
|
|
||||||
public void testAllFilesPresentInTailRecursion() throws Exception {
|
|
||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/box/functions/tailRecursion"), Pattern.compile("^(.+)\\.kt$"), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("defaultArgs.kt")
|
|
||||||
public void testDefaultArgs() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/defaultArgs.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("infixCall.kt")
|
|
||||||
public void testInfixCall() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/infixCall.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("insideElvis.kt")
|
|
||||||
public void testInsideElvis() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/insideElvis.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("labeledThisReferences.kt")
|
|
||||||
public void testLabeledThisReferences() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/labeledThisReferences.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("loops.kt")
|
|
||||||
public void testLoops() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/loops.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("multilevelBlocks.kt")
|
|
||||||
public void testMultilevelBlocks() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/multilevelBlocks.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("realIteratorFoldl.kt")
|
|
||||||
public void testRealIteratorFoldl() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/realIteratorFoldl.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("realStringEscape.kt")
|
|
||||||
public void testRealStringEscape() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/realStringEscape.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("realStringRepeat.kt")
|
|
||||||
public void testRealStringRepeat() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/realStringRepeat.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("recursiveInnerFunction.kt")
|
|
||||||
public void testRecursiveInnerFunction() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/recursiveInnerFunction.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("returnIf.kt")
|
|
||||||
public void testReturnIf() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/returnIf.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("returnInCatch.kt")
|
|
||||||
public void testReturnInCatch() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/returnInCatch.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("returnInFinally.kt")
|
|
||||||
public void testReturnInFinally() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/returnInFinally.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("returnInIfInFinally.kt")
|
|
||||||
public void testReturnInIfInFinally() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/returnInIfInFinally.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("returnInTry.kt")
|
|
||||||
public void testReturnInTry() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/returnInTry.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("simpleBlock.kt")
|
|
||||||
public void testSimpleBlock() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/simpleBlock.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("simpleReturn.kt")
|
|
||||||
public void testSimpleReturn() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/simpleReturn.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("simpleReturnWithElse.kt")
|
|
||||||
public void testSimpleReturnWithElse() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/simpleReturnWithElse.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("thisReferences.kt")
|
|
||||||
public void testThisReferences() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/thisReferences.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("unitBlocks.kt")
|
|
||||||
public void testUnitBlocks() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/unitBlocks.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("whenWithCondition.kt")
|
|
||||||
public void testWhenWithCondition() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/whenWithCondition.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("whenWithInRange.kt")
|
|
||||||
public void testWhenWithInRange() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/whenWithInRange.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("whenWithIs.kt")
|
|
||||||
public void testWhenWithIs() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/whenWithIs.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestMetadata("whenWithoutCondition.kt")
|
|
||||||
public void testWhenWithoutCondition() throws Exception {
|
|
||||||
doTest("compiler/testData/codegen/box/functions/tailRecursion/whenWithoutCondition.kt");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user