diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/RangeContainsLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/RangeContainsLowering.kt index 26303609ae6..a828e78da40 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/RangeContainsLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/RangeContainsLowering.kt @@ -336,7 +336,9 @@ private class Transformer( ).let { if (additionalNotEmptyCondition != null) { // Add additional condition, currently used in `until` ranges (see UntilHandler.kt). - context.andand(additionalNotEmptyCondition, it) + // NOTE: The additional condition must be on the RIGHT side of the &&, to guarantee that the expressions for the bounds + // and argument are evaluated as designed. (See big comment above on expressions with side effects and temp variables.) + context.andand(it, additionalNotEmptyCondition) } else { it } diff --git a/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt index 218a9b24dc2..d28c1f585f1 100644 --- a/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt +++ b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntil.kt @@ -25,6 +25,8 @@ fun x(i: Int): Int { return i } +fun minValue() = Int.MIN_VALUE + fun box(): String { expectOrder("x(0) in low(1) until high(3)", "LHX") { assertFalse(x(0) in low(1) until high(3)) } expectOrder("0 in low(1) until high(3)", "LH") { assertFalse(0 in low(1) until high(3)) } @@ -53,5 +55,20 @@ fun box(): String { expectOrder("x(2) !in 1 until high(3)", "HX") { assertFalse(x(2) !in 1 until high(3)) } expectOrder("x(2) !in low(1) until 3", "LX") { assertFalse(x(2) !in low(1) until 3) } + // For IR backend, there is an additional condition for checking the upper bound == MIN_VALUE (empty range). + // These tests ensure all expressions are evaluated and in the correct order. + expectOrder("0 in low(1) until Int.MIN_VALUE", "L") { assertFalse(0 in low(1) until Int.MIN_VALUE) } + expectOrder("0 in low(1) until minValue()", "L") { assertFalse(0 in low(1) until minValue()) } + expectOrder("x(0) in 1 until Int.MIN_VALUE", "X") { assertFalse(x(0) in 1 until Int.MIN_VALUE) } + expectOrder("x(0) in 1 until minValue()", "X") { assertFalse(x(0) in 1 until minValue()) } + expectOrder("x(0) in low(1) until Int.MIN_VALUE", "LX") { assertFalse(x(0) in low(1) until Int.MIN_VALUE) } + expectOrder("x(0) in low(1) until minValue()", "LX") { assertFalse(x(0) in low(1) until minValue()) } + expectOrder("0 !in low(1) until Int.MIN_VALUE", "L") { assertTrue(0 !in low(1) until Int.MIN_VALUE) } + expectOrder("0 !in low(1) until minValue()", "L") { assertTrue(0 !in low(1) until minValue()) } + expectOrder("x(0) !in 1 until Int.MIN_VALUE", "X") { assertTrue(x(0) !in 1 until Int.MIN_VALUE) } + expectOrder("x(0) !in 1 until minValue()", "X") { assertTrue(x(0) !in 1 until minValue()) } + expectOrder("x(0) !in low(1) until Int.MIN_VALUE", "LX") { assertTrue(x(0) !in low(1) until Int.MIN_VALUE) } + expectOrder("x(0) !in low(1) until minValue()", "LX") { assertTrue(x(0) !in low(1) until minValue()) } + return "OK" } \ No newline at end of file diff --git a/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt index c8a1257d939..e6ae37cdddd 100644 --- a/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt +++ b/compiler/testData/codegen/box/ranges/contains/evaluationOrderForUntilReversed.kt @@ -25,6 +25,8 @@ fun x(i: Int): Int { return i } +fun minValue() = Int.MIN_VALUE + fun box(): String { expectOrder("x(0) in (low(1) until high(3)).reversed()", "LHX") { assertFalse(x(0) in (low(1) until high(3)).reversed()) } expectOrder("0 in (low(1) until high(3)).reversed()", "LH") { assertFalse(0 in (low(1) until high(3)).reversed()) } @@ -53,5 +55,20 @@ fun box(): String { expectOrder("x(2) !in 1 until high(3)", "HX") { assertFalse(x(2) !in 1 until high(3)) } expectOrder("x(2) !in low(1) until 3", "LX") { assertFalse(x(2) !in low(1) until 3) } + // For IR backend, there is an additional condition for checking the upper bound == MIN_VALUE (empty range). + // These tests ensure all expressions are evaluated and in the correct order. + expectOrder("0 in (low(1) until Int.MIN_VALUE).reversed()", "L") { assertFalse(0 in (low(1) until Int.MIN_VALUE).reversed()) } + expectOrder("0 in (low(1) until minValue()).reversed()", "L") { assertFalse(0 in (low(1) until minValue()).reversed()) } + expectOrder("x(0) in (1 until Int.MIN_VALUE).reversed()", "X") { assertFalse(x(0) in (1 until Int.MIN_VALUE).reversed()) } + expectOrder("x(0) in (1 until minValue()).reversed()", "X") { assertFalse(x(0) in (1 until minValue()).reversed()) } + expectOrder("x(0) in (low(1) until Int.MIN_VALUE).reversed()", "LX") { assertFalse(x(0) in (low(1) until Int.MIN_VALUE).reversed()) } + expectOrder("x(0) in (low(1) until minValue()).reversed()", "LX") { assertFalse(x(0) in (low(1) until minValue()).reversed()) } + expectOrder("0 !in (low(1) until Int.MIN_VALUE).reversed()", "L") { assertTrue(0 !in (low(1) until Int.MIN_VALUE).reversed()) } + expectOrder("0 !in (low(1) until minValue()).reversed()", "L") { assertTrue(0 !in (low(1) until minValue()).reversed()) } + expectOrder("x(0) !in (1 until Int.MIN_VALUE).reversed()", "X") { assertTrue(x(0) !in (1 until Int.MIN_VALUE).reversed()) } + expectOrder("x(0) !in (1 until minValue()).reversed()", "X") { assertTrue(x(0) !in (1 until minValue()).reversed()) } + expectOrder("x(0) !in (low(1) until Int.MIN_VALUE).reversed()", "LX") { assertTrue(x(0) !in (low(1) until Int.MIN_VALUE).reversed()) } + expectOrder("x(0) !in (low(1) until minValue()).reversed()", "LX") { assertTrue(x(0) !in (low(1) until minValue()).reversed()) } + return "OK" } \ No newline at end of file