diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionHandlers.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionHandlers.kt index 7fbdf25a47d..d1c77065690 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionHandlers.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/loops/ProgressionHandlers.kt @@ -212,22 +212,19 @@ internal class ArrayIterationHandler(private val context: CommonBackendContext) with(context.createIrBuilder(call.symbol, call.startOffset, call.endOffset)) { // Consider the case like: // - // ``` - // for (elem in A) { f(elem) }` - // ``` + // for (elem in A) { f(elem) }` // // If we lower it to: // - // ``` - // for (i in A.indices) { f(A[i]) } - // ``` + // for (i in A.indices) { f(A[i]) } // // ...then we will break program behaviour if `A` is an expression with side-effect. Instead, we lower it to: // - // ``` - // val a = A - // for (i in a.indices) { f(a[i]) } - // ``` + // val a = A + // for (i in a.indices) { f(a[i]) } + // + // This also ensures that the semantics of re-assignment of array variables used in the loop is consistent with the semantics + // proposed in https://youtrack.jetbrains.com/issue/KT-21354. val arrayReference = scope.createTemporaryVariable( call.dispatchReceiver!!, nameHint = "array", origin = IrDeclarationOrigin.FOR_LOOP_IMPLICIT_VARIABLE diff --git a/compiler/testData/codegen/bytecodeText/forLoop/forInObjectArray.kt b/compiler/testData/codegen/bytecodeText/forLoop/forInObjectArray.kt new file mode 100644 index 00000000000..884c2382e15 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/forInObjectArray.kt @@ -0,0 +1,11 @@ +fun array() = arrayOfNulls(4) + +fun f() { + for (i in array()) { + } +} + +// 0 iterator +// 1 INVOKESTATIC .*\.array \(\) +// 1 ARRAYLENGTH +// 1 IF_ICMP \ No newline at end of file diff --git a/compiler/testData/codegen/bytecodeText/forLoop/forInPrimitiveArray.kt b/compiler/testData/codegen/bytecodeText/forLoop/forInPrimitiveArray.kt new file mode 100644 index 00000000000..439feb54e74 --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/forLoop/forInPrimitiveArray.kt @@ -0,0 +1,16 @@ +fun intArray() = intArrayOf(0, 0, 0, 0) +fun longArray() = longArrayOf(0, 0, 0, 0) + +fun f() { + for (i in intArray()) { + } + + for (i in longArray()) { + } +} + +// 0 iterator +// 1 INVOKESTATIC .*\.intArray \(\) +// 1 INVOKESTATIC .*\.longArray \(\) +// 2 ARRAYLENGTH +// 2 IF_ICMP \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 204a27dcce2..b3b81e1f469 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -1627,11 +1627,21 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/forLoop/forInCharSequence.kt"); } + @TestMetadata("forInObjectArray.kt") + public void testForInObjectArray() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/forInObjectArray.kt"); + } + @TestMetadata("forInOptimizableUnsignedRange.kt") public void testForInOptimizableUnsignedRange() throws Exception { runTest("compiler/testData/codegen/bytecodeText/forLoop/forInOptimizableUnsignedRange.kt"); } + @TestMetadata("forInPrimitiveArray.kt") + public void testForInPrimitiveArray() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/forInPrimitiveArray.kt"); + } + @TestMetadata("forInRangeSpecializedToUntil.kt") public void testForInRangeSpecializedToUntil() throws Exception { runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeSpecializedToUntil.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java index e4843df190e..a1291beace7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBytecodeTextTestGenerated.java @@ -1637,11 +1637,21 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest { runTest("compiler/testData/codegen/bytecodeText/forLoop/forInCharSequence.kt"); } + @TestMetadata("forInObjectArray.kt") + public void testForInObjectArray() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/forInObjectArray.kt"); + } + @TestMetadata("forInOptimizableUnsignedRange.kt") public void testForInOptimizableUnsignedRange() throws Exception { runTest("compiler/testData/codegen/bytecodeText/forLoop/forInOptimizableUnsignedRange.kt"); } + @TestMetadata("forInPrimitiveArray.kt") + public void testForInPrimitiveArray() throws Exception { + runTest("compiler/testData/codegen/bytecodeText/forLoop/forInPrimitiveArray.kt"); + } + @TestMetadata("forInRangeSpecializedToUntil.kt") public void testForInRangeSpecializedToUntil() throws Exception { runTest("compiler/testData/codegen/bytecodeText/forLoop/forInRangeSpecializedToUntil.kt");