Provide optimized code generation for for-in-withIndex for iterables

#KT-5177 In Progress
This commit is contained in:
Dmitry Petrov
2018-01-19 16:17:06 +03:00
parent 08622b0953
commit 9c9e507172
20 changed files with 523 additions and 0 deletions
@@ -143,6 +143,12 @@ fun isArrayOrPrimitiveArrayWithIndex(descriptor: CallableDescriptor) =
KotlinBuiltIns.isArray(it) || KotlinBuiltIns.isPrimitiveArray(it)
}
fun isIterableWithIndex(descriptor: CallableDescriptor) =
descriptor.isTopLevelExtensionOnType("withIndex", "kotlin.collections") {
val typeDescriptor = it.constructor.declarationDescriptor ?: return false
isTopLevelInPackage(typeDescriptor, "Iterable", "kotlin.collections")
}
fun isCollectionIndices(descriptor: CallableDescriptor) =
descriptor.isTopLevelExtensionOnType("indices", "kotlin.collections") {
KotlinBuiltIns.isCollectionOrNullableCollection(it)
@@ -0,0 +1,26 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. 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.codegen.range
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.range.forLoop.ForLoopGenerator
import org.jetbrains.kotlin.codegen.range.forLoop.IterableWithIndexForLoopGenerator
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
class IterableWithIndexRangeValue(rangeCall: ResolvedCall<out CallableDescriptor>) : AbstractDestructuredPairRangeValue(rangeCall) {
override fun createDestructuredPairForLoopGenerator(
codegen: ExpressionCodegen,
forExpression: KtForExpression,
loopParameter: KtDestructuringDeclaration,
rangeCall: ResolvedCall<out CallableDescriptor>
): ForLoopGenerator =
IterableWithIndexForLoopGenerator(codegen, forExpression, loopParameter, rangeCall)
}
@@ -128,6 +128,8 @@ private fun ExpressionCodegen.createIntrinsifiedRangeValueOrNull(rangeCall: Reso
CharSequenceIndicesRangeValue(rangeCall)
isArrayOrPrimitiveArrayWithIndex(rangeCallee) ->
ArrayWithIndexRangeValue(rangeCall)
isIterableWithIndex(rangeCallee) ->
IterableWithIndexRangeValue(rangeCall)
isComparableRangeTo(rangeCallee) ->
ComparableRangeLiteralRangeValue(this, rangeCall)
isPrimitiveProgressionReverse(rangeCallee) ->
@@ -0,0 +1,65 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. 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.codegen.range.forLoop
import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.generateCallReceiver
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
class IterableWithIndexForLoopGenerator(
codegen: ExpressionCodegen,
forExpression: KtForExpression,
loopParameter: KtDestructuringDeclaration,
rangeCall: ResolvedCall<out CallableDescriptor>
) : AbstractWithIndexForLoopGenerator(codegen, forExpression, loopParameter, rangeCall) {
private var iteratorVar = -1
private var indexVar = -1
private var indexType = Type.INT_TYPE
private val asmTypeForIterator = Type.getType(Iterator::class.java)
override fun beforeLoop() {
indexVar = indexLoopComponent?.parameterVar ?: createLoopTempVariable(Type.INT_TYPE)
indexType = indexLoopComponent?.parameterType ?: Type.INT_TYPE
StackValue.local(indexVar, indexType)
.store(StackValue.constant(0, Type.INT_TYPE), v)
iteratorVar = createLoopTempVariable(asmTypeForIterator)
codegen.generateCallReceiver(rangeCall).put(Type.getType(Iterable::class.java), v)
v.invokeinterface("java/lang/Iterable", "iterator", "()Ljava/util/Iterator;")
StackValue.local(iteratorVar, asmTypeForIterator).store(StackValue.onStack(asmTypeForIterator), v)
}
override fun checkPreCondition(loopExit: Label) {
v.load(iteratorVar, asmTypeForIterator)
v.invokeinterface("java/util/Iterator", "hasNext", "()Z")
v.ifeq(loopExit)
}
override fun assignLoopParametersNextValues() {
v.load(iteratorVar, asmTypeForIterator)
v.invokeinterface("java/util/Iterator", "next", "()Ljava/lang/Object;")
if (elementLoopComponent != null) {
StackValue.local(elementLoopComponent.parameterVar, elementLoopComponent.parameterType)
.store(StackValue.onStack(AsmTypes.OBJECT_TYPE), v)
} else {
v.pop()
}
}
override fun incrementAndCheckPostCondition(loopExit: Label) {
v.iinc(indexVar, 1)
}
}
@@ -0,0 +1,11 @@
// WITH_RUNTIME
val xs = listOf<Any>()
fun box(): String {
val s = StringBuilder()
for ((index, x) in xs.withIndex()) {
return "Loop over empty list should not be executed"
}
return "OK"
}
@@ -0,0 +1,14 @@
// WITH_RUNTIME
val xs = listOf("a", "b", "c", "d")
fun box(): String {
val s = StringBuilder()
for ((index, x) in xs.withIndex()) {
s.append("$index:$x;")
}
val ss = s.toString()
return if (ss == "0:a;1:b;2:c;3:d;") "OK" else "fail: '$ss'"
}
@@ -0,0 +1,14 @@
// WITH_RUNTIME
val xs = listOf("a", "b", "c", "d")
fun box(): String {
val s = StringBuilder()
for ((i, _) in xs.withIndex()) {
s.append("$i;")
}
val ss = s.toString()
return if (ss == "0;1;2;3;") "OK" else "fail: '$ss'"
}
@@ -0,0 +1,14 @@
// WITH_RUNTIME
val xs = listOf("a", "b", "c", "d")
fun box(): String {
val s = StringBuilder()
for ((_, x) in xs.withIndex()) {
s.append("$x;")
}
val ss = s.toString()
return if (ss == "a;b;c;d;") "OK" else "fail: '$ss'"
}
@@ -0,0 +1,24 @@
// IGNORE_BACKEND: JS, NATIVE
// FULL_JDK
// WITH_RUNTIME
val xs = arrayListOf("a", "b", "c", "d")
fun box(): String {
val s = StringBuilder()
var cmeThrown = false
try {
for ((index, x) in xs.withIndex()) {
s.append("$index:$x;")
xs.clear()
}
} catch (e: java.util.ConcurrentModificationException) {
cmeThrown = true
}
if (!cmeThrown) return "Fail: CME should be thrown"
val ss = s.toString()
return if (ss == "0:a;") "OK" else "fail: '$ss'"
}
@@ -0,0 +1,17 @@
// WITH_RUNTIME
val xs = listOf("a", "b", "c", "d")
fun useAny(x: Any) {}
fun box(): String {
val s = StringBuilder()
for ((index: Any, x) in xs.withIndex()) {
useAny(index)
s.append("$index:$x;")
}
val ss = s.toString()
return if (ss == "0:a;1:b;2:c;3:d;") "OK" else "fail: '$ss'"
}
@@ -0,0 +1,18 @@
// WITH_RUNTIME
val xs = listOf<Any>()
fun box(): String {
val s = StringBuilder()
for ((index, x) in xs.withIndex()) {
return "Loop over empty array should not be executed"
}
return "OK"
}
// 0 withIndex
// 1 iterator
// 1 hasNext
// 1 next
// 0 component1
// 0 component2
@@ -0,0 +1,21 @@
// WITH_RUNTIME
val xs = listOf("a", "b", "c", "d")
fun box(): String {
val s = StringBuilder()
for ((index, x) in xs.withIndex()) {
s.append("$index:$x;")
}
val ss = s.toString()
return if (ss == "0:a;1:b;2:c;3:d;") "OK" else "fail: '$ss'"
}
// 0 withIndex
// 1 iterator
// 1 hasNext
// 1 next
// 0 component1
// 0 component2
@@ -0,0 +1,21 @@
// WITH_RUNTIME
val xs = listOf("a", "b", "c", "d")
fun box(): String {
val s = StringBuilder()
for ((i, _) in xs.withIndex()) {
s.append("$i;")
}
val ss = s.toString()
return if (ss == "0;1;2;3;") "OK" else "fail: '$ss'"
}
// 0 withIndex
// 1 iterator
// 1 hasNext
// 1 next
// 0 component1
// 0 component2
@@ -0,0 +1,21 @@
// WITH_RUNTIME
val xs = listOf("a", "b", "c", "d")
fun box(): String {
val s = StringBuilder()
for ((_, x) in xs.withIndex()) {
s.append("$x;")
}
val ss = s.toString()
return if (ss == "a;b;c;d;") "OK" else "fail: '$ss'"
}
// 0 withIndex
// 1 iterator
// 1 hasNext
// 1 next
// 0 component1
// 0 component2
@@ -0,0 +1,24 @@
// WITH_RUNTIME
val xs = listOf("a", "b", "c", "d")
fun useAny(x: Any) {}
fun box(): String {
val s = StringBuilder()
for ((index: Any, x) in xs.withIndex()) {
useAny(index)
s.append("$index:$x;")
}
val ss = s.toString()
return if (ss == "0:a;1:b;2:c;3:d;") "OK" else "fail: '$ss'"
}
// 0 withIndex
// 1 iterator
// 1 hasNext
// 1 next
// 0 component1
// 0 component2
@@ -5223,6 +5223,51 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
}
}
@TestMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ForInIterableWithIndex extends AbstractIrBlackBoxCodegenTest {
public void testAllFilesPresentInForInIterableWithIndex() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("forInEmptyListWithIndex.kt")
public void testForInEmptyListWithIndex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInEmptyListWithIndex.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndex.kt")
public void testForInListWithIndex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndex.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexNoElementVar.kt")
public void testForInListWithIndexNoElementVar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexNoElementVar.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexNoIndexVar.kt")
public void testForInListWithIndexNoIndexVar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexNoIndexVar.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexThrowsCME.kt")
public void testForInListWithIndexThrowsCME() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexThrowsCME.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexWithExplicitlyTypedIndexVariable.kt")
public void testForInListWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexWithExplicitlyTypedIndexVariable.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/controlStructures/returnsNothing")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -5223,6 +5223,51 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
}
}
@TestMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ForInIterableWithIndex extends AbstractBlackBoxCodegenTest {
public void testAllFilesPresentInForInIterableWithIndex() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("forInEmptyListWithIndex.kt")
public void testForInEmptyListWithIndex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInEmptyListWithIndex.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndex.kt")
public void testForInListWithIndex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndex.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexNoElementVar.kt")
public void testForInListWithIndexNoElementVar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexNoElementVar.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexNoIndexVar.kt")
public void testForInListWithIndexNoIndexVar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexNoIndexVar.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexThrowsCME.kt")
public void testForInListWithIndexThrowsCME() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexThrowsCME.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexWithExplicitlyTypedIndexVariable.kt")
public void testForInListWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexWithExplicitlyTypedIndexVariable.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/controlStructures/returnsNothing")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -1452,6 +1452,45 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInIterableWithIndex")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ForInIterableWithIndex extends AbstractBytecodeTextTest {
public void testAllFilesPresentInForInIterableWithIndex() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/forLoop/forInIterableWithIndex"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("forInEmptyListWithIndex.kt")
public void testForInEmptyListWithIndex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInIterableWithIndex/forInEmptyListWithIndex.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndex.kt")
public void testForInListWithIndex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInIterableWithIndex/forInListWithIndex.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexNoElementVar.kt")
public void testForInListWithIndexNoElementVar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInIterableWithIndex/forInListWithIndexNoElementVar.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexNoIndexVar.kt")
public void testForInListWithIndexNoIndexVar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInIterableWithIndex/forInListWithIndexNoIndexVar.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexWithExplicitlyTypedIndexVariable.kt")
public void testForInListWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInIterableWithIndex/forInListWithIndexWithExplicitlyTypedIndexVariable.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInReversed")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -5223,6 +5223,51 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
}
}
@TestMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ForInIterableWithIndex extends AbstractLightAnalysisModeTest {
public void testAllFilesPresentInForInIterableWithIndex() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
}
@TestMetadata("forInEmptyListWithIndex.kt")
public void testForInEmptyListWithIndex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInEmptyListWithIndex.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndex.kt")
public void testForInListWithIndex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndex.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexNoElementVar.kt")
public void testForInListWithIndexNoElementVar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexNoElementVar.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexNoIndexVar.kt")
public void testForInListWithIndexNoIndexVar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexNoIndexVar.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexThrowsCME.kt")
public void testForInListWithIndexThrowsCME() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexThrowsCME.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexWithExplicitlyTypedIndexVariable.kt")
public void testForInListWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexWithExplicitlyTypedIndexVariable.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/controlStructures/returnsNothing")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -5805,6 +5805,57 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
}
}
@TestMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ForInIterableWithIndex extends AbstractJsCodegenBoxTest {
public void testAllFilesPresentInForInIterableWithIndex() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("forInEmptyListWithIndex.kt")
public void testForInEmptyListWithIndex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInEmptyListWithIndex.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndex.kt")
public void testForInListWithIndex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndex.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexNoElementVar.kt")
public void testForInListWithIndexNoElementVar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexNoElementVar.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexNoIndexVar.kt")
public void testForInListWithIndexNoIndexVar() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexNoIndexVar.kt");
doTest(fileName);
}
@TestMetadata("forInListWithIndexThrowsCME.kt")
public void testForInListWithIndexThrowsCME() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexThrowsCME.kt");
try {
doTest(fileName);
}
catch (Throwable ignore) {
return;
}
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
}
@TestMetadata("forInListWithIndexWithExplicitlyTypedIndexVariable.kt")
public void testForInListWithIndexWithExplicitlyTypedIndexVariable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/controlStructures/forInIterableWithIndex/forInListWithIndexWithExplicitlyTypedIndexVariable.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/controlStructures/returnsNothing")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)