diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeSteppingTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeSteppingTestGenerated.java index ba61c8d7621..2d6ae691ab2 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeSteppingTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirLightTreeSteppingTestGenerated.java @@ -601,6 +601,48 @@ public class FirLightTreeSteppingTestGenerated extends AbstractFirLightTreeStepp runTest("compiler/testData/debug/stepping/whenExpr.kt"); } + @Test + @TestMetadata("whenInConjunction.kt") + public void testWhenInConjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInConjunction.kt"); + } + + @Test + @TestMetadata("whenInDisjunction.kt") + public void testWhenInDisjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInDisjunction.kt"); + } + + @Test + @TestMetadata("whenInGeneralObjectComparison.kt") + public void testWhenInGeneralObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInGeneralObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInNegation.kt") + public void testWhenInNegation() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNegation.kt"); + } + + @Test + @TestMetadata("whenInNullComparison.kt") + public void testWhenInNullComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNullComparison.kt"); + } + + @Test + @TestMetadata("whenInPrimitiveToObjectComparison.kt") + public void testWhenInPrimitiveToObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInPrimitiveToObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInZeroComparison.kt") + public void testWhenInZeroComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInZeroComparison.kt"); + } + @Test @TestMetadata("whenIsChecks.kt") public void testWhenIsChecks() throws Exception { diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiSteppingTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiSteppingTestGenerated.java index ddf501ae4dc..7c99979d575 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiSteppingTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirPsiSteppingTestGenerated.java @@ -601,6 +601,48 @@ public class FirPsiSteppingTestGenerated extends AbstractFirPsiSteppingTest { runTest("compiler/testData/debug/stepping/whenExpr.kt"); } + @Test + @TestMetadata("whenInConjunction.kt") + public void testWhenInConjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInConjunction.kt"); + } + + @Test + @TestMetadata("whenInDisjunction.kt") + public void testWhenInDisjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInDisjunction.kt"); + } + + @Test + @TestMetadata("whenInGeneralObjectComparison.kt") + public void testWhenInGeneralObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInGeneralObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInNegation.kt") + public void testWhenInNegation() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNegation.kt"); + } + + @Test + @TestMetadata("whenInNullComparison.kt") + public void testWhenInNullComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNullComparison.kt"); + } + + @Test + @TestMetadata("whenInPrimitiveToObjectComparison.kt") + public void testWhenInPrimitiveToObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInPrimitiveToObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInZeroComparison.kt") + public void testWhenInZeroComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInZeroComparison.kt"); + } + @Test @TestMetadata("whenIsChecks.kt") public void testWhenIsChecks() throws Exception { diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt index 8b314aba104..915d4abb1a1 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/codegen/PromisedValue.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.ir.declarations.IrTypeParameter import org.jetbrains.kotlin.ir.declarations.isSingleFieldValueClass +import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.isTypeParameter @@ -110,6 +111,12 @@ abstract class BooleanValue(codegen: ExpressionCodegen) : StackValue.coerce(Type.BOOLEAN_TYPE, target, mv) } } + + fun markLineNumber(expression: IrExpression) { + with(codegen) { + expression.markLineNumber(startOffset = true) + } + } } class BooleanConstant(codegen: ExpressionCodegen, val value: Boolean) : BooleanValue(codegen) { diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/AndAnd.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/AndAnd.kt index 3bc23b662c5..c3c8a213801 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/AndAnd.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/AndAnd.kt @@ -12,25 +12,41 @@ import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.org.objectweb.asm.Label object AndAnd : IntrinsicMethod() { - private class BooleanConjunction(val arg0: IrExpression, val arg1: IrExpression, codegen: ExpressionCodegen, val data: BlockInfo) : - BooleanValue(codegen) { + private class BooleanConjunction( + val left: IrExpression, + val right: IrExpression, + codegen: ExpressionCodegen, + val data: BlockInfo + ) : BooleanValue(codegen) { override fun jumpIfFalse(target: Label) { - arg0.accept(codegen, data).coerceToBoolean().jumpIfFalse(target) - arg1.accept(codegen, data).coerceToBoolean().jumpIfFalse(target) + val leftValue = left.accept(codegen, data).coerceToBoolean() + markLineNumber(left) + leftValue.jumpIfFalse(target) + val rightValue = right.accept(codegen, data).coerceToBoolean() + markLineNumber(right) + rightValue.jumpIfFalse(target) } override fun jumpIfTrue(target: Label) { val stayLabel = Label() - arg0.accept(codegen, data).coerceToBoolean().jumpIfFalse(stayLabel) - arg1.accept(codegen, data).coerceToBoolean().jumpIfTrue(target) + val leftValue = left.accept(codegen, data).coerceToBoolean() + markLineNumber(left) + leftValue.jumpIfFalse(stayLabel) + val rightValue = right.accept(codegen, data).coerceToBoolean() + markLineNumber(right) + rightValue.jumpIfTrue(target) mv.visitLabel(stayLabel) } override fun discard() { val end = Label() - arg0.accept(codegen, data).coerceToBoolean().jumpIfFalse(end) - arg1.accept(codegen, data).discard() + val leftValue = left.accept(codegen, data).coerceToBoolean() + markLineNumber(left) + leftValue.jumpIfFalse(end) + val rightValue = right.accept(codegen, data) + markLineNumber(right) + rightValue.discard() mv.visitLabel(end) } } diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/CompareTo.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/CompareTo.kt index 56a9992b360..5afb77a2103 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/CompareTo.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/CompareTo.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.codegen.BranchedValue import org.jetbrains.kotlin.codegen.NumberCompare import org.jetbrains.kotlin.codegen.ObjectCompare import org.jetbrains.kotlin.config.LanguageFeature +import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.lexer.KtSingleValueToken import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType @@ -67,27 +68,37 @@ object CompareTo : IntrinsicMethod() { } } -class IntegerZeroComparison(val a: MaterialValue) : BooleanValue(a.codegen) { +class IntegerZeroComparison(val nonZeroExpression: IrExpression, val a: MaterialValue) : BooleanValue(a.codegen) { + override fun jumpIfFalse(target: Label) { + markLineNumber(nonZeroExpression) mv.visitJumpInsn(Opcodes.IFNE, target) } override fun jumpIfTrue(target: Label) { + markLineNumber(nonZeroExpression) mv.visitJumpInsn(Opcodes.IFEQ, target) } override fun discard() { + markLineNumber(nonZeroExpression) a.discard() } } -class BooleanComparison(val op: IElementType, val a: MaterialValue, val b: MaterialValue) : BooleanValue(a.codegen) { +class BooleanComparison( + val expression: IrFunctionAccessExpression, + val op: IElementType, + val a: MaterialValue, + val b: MaterialValue +) : BooleanValue(a.codegen) { override fun jumpIfFalse(target: Label) { // TODO 1. get rid of the dependency; 2. take `b.type` into account. val opcode = if (a.type.sort == Type.OBJECT) ObjectCompare.getObjectCompareOpcode(op) else NumberCompare.patchOpcode(NumberCompare.getNumberCompareOpcode(op), mv, op, a.type) + markLineNumber(expression) mv.visitJumpInsn(opcode, target) } @@ -96,17 +107,23 @@ class BooleanComparison(val op: IElementType, val a: MaterialValue, val b: Mater BranchedValue.negatedOperations[ObjectCompare.getObjectCompareOpcode(op)]!! else NumberCompare.patchOpcode(BranchedValue.negatedOperations[NumberCompare.getNumberCompareOpcode(op)]!!, mv, op, a.type) + markLineNumber(expression) mv.visitJumpInsn(opcode, target) } override fun discard() { + markLineNumber(expression) b.discard() a.discard() } } - -class NonIEEE754FloatComparison(op: IElementType, private val a: MaterialValue, private val b: MaterialValue) : BooleanValue(a.codegen) { +class NonIEEE754FloatComparison( + private val expression: IrFunctionAccessExpression, + op: IElementType, + private val a: MaterialValue, + private val b: MaterialValue +) : BooleanValue(a.codegen) { private val numberCompareOpcode = NumberCompare.getNumberCompareOpcode(op) private fun invokeStaticComparison(type: Type) { @@ -118,22 +135,26 @@ class NonIEEE754FloatComparison(op: IElementType, private val a: MaterialValue, } override fun jumpIfFalse(target: Label) { + markLineNumber(expression) invokeStaticComparison(a.type) mv.visitJumpInsn(numberCompareOpcode, target) } override fun jumpIfTrue(target: Label) { + markLineNumber(expression) invokeStaticComparison(a.type) mv.visitJumpInsn(BranchedValue.negatedOperations[numberCompareOpcode]!!, target) } override fun discard() { + markLineNumber(expression) b.discard() a.discard() } } class PrimitiveToObjectComparison( + private val expression: IrFunctionAccessExpression, private val op: IElementType, private val leftIsPrimitive: Boolean, private val left: MaterialValue, @@ -159,26 +180,31 @@ class PrimitiveToObjectComparison( mv.mark(compareLabel) // Type checking OK, can unbox and compare: return if (leftIsPrimitive) { - BooleanComparison(op, left, right.materializedAt(left.type, right.irType)) + BooleanComparison(expression, op, left, right.materializedAt(left.type, right.irType)) } else { val leftUnboxed = left.materializedAt(right.type, left.irType) mv.load(tmp, right.type) codegen.frameMap.leaveTemp(right.type) - BooleanComparison(op, leftUnboxed, right) + BooleanComparison(expression, op, leftUnboxed, right) } } override fun jumpIfFalse(target: Label) { - checkTypeAndCompare(target).jumpIfFalse(target) + markLineNumber(expression) + val comparison = checkTypeAndCompare(target) + comparison.jumpIfFalse(target) } override fun jumpIfTrue(target: Label) { + markLineNumber(expression) val wrongType = Label() - checkTypeAndCompare(wrongType).jumpIfTrue(target) + val comparison = checkTypeAndCompare(wrongType) + comparison.jumpIfTrue(target) mv.mark(wrongType) } override fun discard() { + markLineNumber(expression) right.discard() left.discard() } @@ -200,9 +226,9 @@ class PrimitiveComparison( && (left.isSmartcastFromHigherThanNullable(codegen.context) || right.isSmartcastFromHigherThanNullable(codegen.context)) return if (useNonIEEE754Comparison) { - NonIEEE754FloatComparison(operatorToken, a, b) + NonIEEE754FloatComparison(expression, operatorToken, a, b) } else { - BooleanComparison(operatorToken, a, b) + BooleanComparison(expression, operatorToken, a, b) } } } diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/Equals.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/Equals.kt index 138133bf859..d80d56b3534 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/Equals.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/Equals.kt @@ -57,10 +57,21 @@ class ExplicitEquals : IntrinsicMethod() { class Equals(val operator: IElementType) : IntrinsicMethod() { - private class BooleanNullCheck(val value: PromisedValue) : BooleanValue(value.codegen) { - override fun jumpIfFalse(target: Label) = value.materialize().also { mv.ifnonnull(target) } - override fun jumpIfTrue(target: Label) = value.materialize().also { mv.ifnull(target) } + private class BooleanNullCheck(val expression: IrFunctionAccessExpression, val value: PromisedValue) : BooleanValue(value.codegen) { + override fun jumpIfFalse(target: Label) { + value.materialize() + markLineNumber(expression) + mv.ifnonnull(target) + } + + override fun jumpIfTrue(target: Label) { + value.materialize() + markLineNumber(expression) + mv.ifnull(target) + } + override fun discard() { + markLineNumber(expression) value.discard() } } @@ -71,7 +82,7 @@ class Equals(val operator: IElementType) : IntrinsicMethod() { val irValue = if (a.isNullConst()) b else a val value = irValue.accept(codegen, data) return if (!isPrimitive(value.type) && (irValue.type.classOrNull?.owner?.isSingleFieldValueClass != true || irValue.type.isNullable())) - BooleanNullCheck(value) + BooleanNullCheck(expression, value) else { value.discard() BooleanConstant(codegen, false) @@ -80,7 +91,7 @@ class Equals(val operator: IElementType) : IntrinsicMethod() { val leftType = codegen.typeMapper.mapTypeAsDeclaration(a.type) if (expression.origin == IrStatementOrigin.EQEQEQ || expression.origin == IrStatementOrigin.EXCLEQEQ) { - return referenceEquals(a, b, leftType, codegen, data) + return referenceEquals(expression, a, b, leftType, codegen, data) } val rightType = codegen.typeMapper.mapTypeAsDeclaration(b.type) @@ -93,7 +104,7 @@ class Equals(val operator: IElementType) : IntrinsicMethod() { ) { val aValue = a.accept(codegen, data).materializedAt(leftType, a.type) val bValue = b.accept(codegen, data).materializedAt(rightType, b.type) - return PrimitiveToObjectComparison(operator, AsmUtil.isIntOrLongPrimitive(leftType), aValue, bValue) + return PrimitiveToObjectComparison(expression, operator, AsmUtil.isIntOrLongPrimitive(leftType), aValue, bValue) } if (isPrimitive(leftType) && leftType == rightType) { @@ -101,26 +112,29 @@ class Equals(val operator: IElementType) : IntrinsicMethod() { return if (leftType == Type.FLOAT_TYPE || leftType == Type.DOUBLE_TYPE) { val aValue = a.accept(codegen, data).materializedAt(leftType, a.type) val bValue = b.accept(codegen, data).materializedAt(rightType, b.type) - return NonIEEE754FloatComparison(operator, aValue, bValue) + return NonIEEE754FloatComparison(expression, operator, aValue, bValue) } else { - referenceEquals(a, b, leftType, codegen, data) + referenceEquals(expression, a, b, leftType, codegen, data) } } // We can use reference equality for enums, otherwise we fall back to boxed equality. return when { a.isEnumValue || b.isEnumValue -> - referenceEquals(a, b, leftType, codegen, data) + referenceEquals(expression, a, b, leftType, codegen, data) a.isClassValue && b.isClassValue -> { val leftValue = codegen.generateClassLiteralReference(a, wrapIntoKClass = false, wrapPrimitives = true, data = data) val rightValue = codegen.generateClassLiteralReference(b, wrapIntoKClass = false, wrapPrimitives = true, data = data) - BooleanComparison(operator, leftValue, rightValue) + BooleanComparison(expression, operator, leftValue, rightValue) } else -> { a.accept(codegen, data).materializeAt(AsmTypes.OBJECT_TYPE, codegen.context.irBuiltIns.anyNType) b.accept(codegen, data).materializeAt(AsmTypes.OBJECT_TYPE, codegen.context.irBuiltIns.anyNType) + with(codegen) { + expression.markLineNumber(startOffset = true) + } genAreEqualCall(codegen.mv) MaterialValue(codegen, Type.BOOLEAN_TYPE, codegen.context.irBuiltIns.booleanType) } @@ -128,6 +142,7 @@ class Equals(val operator: IElementType) : IntrinsicMethod() { } private fun referenceEquals( + expression: IrFunctionAccessExpression, left: IrExpression, right: IrExpression, leftType: Type, @@ -137,11 +152,11 @@ class Equals(val operator: IElementType) : IntrinsicMethod() { val operandType = if (!isPrimitive(leftType)) AsmTypes.OBJECT_TYPE else leftType return if (operandType == Type.INT_TYPE && (left.isIntegerConst(0) || right.isIntegerConst(0))) { val nonZero = if (left.isIntegerConst(0)) right else left - IntegerZeroComparison(nonZero.accept(codegen, data).materializedAt(operandType, nonZero.type)) + IntegerZeroComparison(expression, nonZero.accept(codegen, data).materializedAt(operandType, nonZero.type)) } else { val leftValue = left.accept(codegen, data).materializedAt(operandType, left.type) val rightValue = right.accept(codegen, data).materializedAt(operandType, right.type) - BooleanComparison(operator, leftValue, rightValue) + BooleanComparison(expression, operator, leftValue, rightValue) } } diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/Not.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/Not.kt index 49a316fccda..b2db2c86b89 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/Not.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/Not.kt @@ -22,16 +22,26 @@ import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen import org.jetbrains.kotlin.backend.jvm.codegen.coerceToBoolean import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.org.objectweb.asm.Label +import kotlin.math.exp object Not : IntrinsicMethod() { - class BooleanNegation(val value: BooleanValue) : BooleanValue(value.codegen) { - override fun jumpIfFalse(target: Label) = value.jumpIfTrue(target) - override fun jumpIfTrue(target: Label) = value.jumpIfFalse(target) + class BooleanNegation(val expression: IrFunctionAccessExpression, val value: BooleanValue) : BooleanValue(value.codegen) { + override fun jumpIfFalse(target: Label) { + markLineNumber(expression) + value.jumpIfTrue(target) + } + + override fun jumpIfTrue(target: Label) { + markLineNumber(expression) + value.jumpIfFalse(target) + } + override fun discard() { + markLineNumber(expression) value.discard() } } override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo) = - BooleanNegation(expression.dispatchReceiver!!.accept(codegen, data).coerceToBoolean()) + BooleanNegation(expression, expression.dispatchReceiver!!.accept(codegen, data).coerceToBoolean()) } diff --git a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/OrOr.kt b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/OrOr.kt index 548f02860ae..2dd2fb72547 100644 --- a/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/OrOr.kt +++ b/compiler/ir/backend.jvm/codegen/src/org/jetbrains/kotlin/backend/jvm/intrinsics/OrOr.kt @@ -14,25 +14,37 @@ import org.jetbrains.org.objectweb.asm.Label object OrOr : IntrinsicMethod() { private class BooleanDisjunction( - val arg0: IrExpression, val arg1: IrExpression, codegen: ExpressionCodegen, val data: BlockInfo + val left: IrExpression, val right: IrExpression, codegen: ExpressionCodegen, val data: BlockInfo ) : BooleanValue(codegen) { override fun jumpIfFalse(target: Label) { val stayLabel = Label() - arg0.accept(codegen, data).coerceToBoolean().jumpIfTrue(stayLabel) - arg1.accept(codegen, data).coerceToBoolean().jumpIfFalse(target) + val leftValue = left.accept(codegen, data).coerceToBoolean() + markLineNumber(left) + leftValue.jumpIfTrue(stayLabel) + val rightValue = right.accept(codegen, data).coerceToBoolean() + markLineNumber(right) + rightValue.jumpIfFalse(target) mv.visitLabel(stayLabel) } override fun jumpIfTrue(target: Label) { - arg0.accept(codegen, data).coerceToBoolean().jumpIfTrue(target) - arg1.accept(codegen, data).coerceToBoolean().jumpIfTrue(target) + val leftValue = left.accept(codegen, data).coerceToBoolean() + markLineNumber(left) + leftValue.jumpIfTrue(target) + val rightValue = right.accept(codegen, data).coerceToBoolean() + markLineNumber(right) + rightValue.jumpIfTrue(target) } override fun discard() { val end = Label() - arg0.accept(codegen, data).coerceToBoolean().jumpIfTrue(end) - arg1.accept(codegen, data).discard() + val leftValue = left.accept(codegen, data).coerceToBoolean() + markLineNumber(left) + leftValue.jumpIfTrue(end) + val rightValue = right.accept(codegen, data) + markLineNumber(right) + rightValue.discard() mv.visitLabel(end) } } diff --git a/compiler/testData/debug/stepping/if.kt b/compiler/testData/debug/stepping/if.kt index 8583007d9e2..2fa63b3cc63 100644 --- a/compiler/testData/debug/stepping/if.kt +++ b/compiler/testData/debug/stepping/if.kt @@ -20,7 +20,7 @@ inline fun getB(): Int { // test.kt:15 box // test.kt:7 box // test.kt:12 getA -// test.kt:7 box +// test.kt:6 box // test.kt:9 box // test.kt:15 box // test.kt:9 box diff --git a/compiler/testData/debug/stepping/whenInConjunction.kt b/compiler/testData/debug/stepping/whenInConjunction.kt new file mode 100644 index 00000000000..f08e2cb4438 --- /dev/null +++ b/compiler/testData/debug/stepping/whenInConjunction.kt @@ -0,0 +1,43 @@ +// IGNORE_BACKEND: WASM +// FILE: test.kt + +fun foo(n: Number) { + if (n.toInt() > 1 && when (n) { + is Float -> true + else -> false + }) { + } + if (when (n) { + is Float -> true + else -> false + } && n.toInt() > 1) { + } +} + +fun box() { + foo(2.0f) +} + +// EXPECTATIONS JVM_IR +// test.kt:18 box +// test.kt:5 foo +// test.kt:6 foo +// test.kt:5 foo +// test.kt:10 foo +// test.kt:11 foo +// test.kt:10 foo +// test.kt:13 foo +// test.kt:15 foo +// test.kt:19 box + +// EXPECTATIONS JS_IR +// test.kt:18 box +// test.kt:5 foo +// test.kt:6 foo +// test.kt:6 foo +// test.kt:11 foo +// test.kt:11 foo +// test.kt:10 foo +// test.kt:13 foo +// test.kt:15 foo +// test.kt:19 box diff --git a/compiler/testData/debug/stepping/whenInDisjunction.kt b/compiler/testData/debug/stepping/whenInDisjunction.kt new file mode 100644 index 00000000000..84a791141ed --- /dev/null +++ b/compiler/testData/debug/stepping/whenInDisjunction.kt @@ -0,0 +1,43 @@ +// IGNORE_BACKEND: WASM +// FILE: test.kt + +fun foo(n: Number) { + if (n.toInt() < 1 || when (n) { + is Float -> false + else -> true + }) { + } + if (when (n) { + is Float -> false + else -> true + } || n.toInt() > 1) { + } +} + +fun box() { + foo(2.0f) +} + +// EXPECTATIONS JVM_IR +// test.kt:18 box +// test.kt:5 foo +// test.kt:6 foo +// test.kt:5 foo +// test.kt:10 foo +// test.kt:11 foo +// test.kt:10 foo +// test.kt:13 foo +// test.kt:15 foo +// test.kt:19 box + +// EXPECTATIONS JS_IR +// test.kt:18 box +// test.kt:5 foo +// test.kt:6 foo +// test.kt:6 foo +// test.kt:11 foo +// test.kt:11 foo +// test.kt:10 foo +// test.kt:13 foo +// test.kt:15 foo +// test.kt:19 box diff --git a/compiler/testData/debug/stepping/whenInGeneralObjectComparison.kt b/compiler/testData/debug/stepping/whenInGeneralObjectComparison.kt new file mode 100644 index 00000000000..26c0ed011c8 --- /dev/null +++ b/compiler/testData/debug/stepping/whenInGeneralObjectComparison.kt @@ -0,0 +1,65 @@ +// IGNORE_BACKEND: WASM +// FILE: test.kt + +fun foo(n: Any, other: Any) { + if (other == when (n) { + is Int -> n + else -> 1.0f + }) { + } + if (when (n) { + is Int -> n + else -> 1.0f + } == other) { + } + if (other != when (n) { + is Int -> n + else -> 1.0f + }) { + } + if (when (n) { + is Int -> n + else -> 1.0f + } != other) { + } +} + +fun box() { + foo(2, Any()) +} + +// EXPECTATIONS JVM_IR +// test.kt:28 box +// test.kt:5 foo +// test.kt:6 foo +// test.kt:5 foo +// test.kt:10 foo +// test.kt:11 foo +// test.kt:13 foo +// test.kt:10 foo +// test.kt:15 foo +// test.kt:16 foo +// test.kt:15 foo +// test.kt:20 foo +// test.kt:21 foo +// test.kt:23 foo +// test.kt:20 foo +// test.kt:25 foo +// test.kt:29 box + +// EXPECTATIONS JS_IR +// test.kt:28 box +// test.kt:6 foo +// test.kt:6 foo +// test.kt:5 foo +// test.kt:11 foo +// test.kt:11 foo +// test.kt:10 foo +// test.kt:16 foo +// test.kt:16 foo +// test.kt:15 foo +// test.kt:21 foo +// test.kt:21 foo +// test.kt:20 foo +// test.kt:25 foo +// test.kt:29 box diff --git a/compiler/testData/debug/stepping/whenInNegation.kt b/compiler/testData/debug/stepping/whenInNegation.kt new file mode 100644 index 00000000000..29099f2cfed --- /dev/null +++ b/compiler/testData/debug/stepping/whenInNegation.kt @@ -0,0 +1,29 @@ +// IGNORE_BACKEND: WASM +// FILE: test.kt + +fun foo(n: Number) { + if (!when (n) { + is Float -> false + else -> true + }) { + } +} + +fun box() { + foo(2.0f) +} + +// EXPECTATIONS JVM_IR +// test.kt:13 box +// test.kt:5 foo +// test.kt:6 foo +// test.kt:5 foo +// test.kt:10 foo +// test.kt:14 box + +// EXPECTATIONS JS_IR +// test.kt:13 box +// test.kt:6 foo +// test.kt:6 foo +// test.kt:10 foo +// test.kt:14 box diff --git a/compiler/testData/debug/stepping/whenInNullComparison.kt b/compiler/testData/debug/stepping/whenInNullComparison.kt new file mode 100644 index 00000000000..fa4050fc76a --- /dev/null +++ b/compiler/testData/debug/stepping/whenInNullComparison.kt @@ -0,0 +1,39 @@ +// IGNORE_BACKEND: WASM +// FILE: test.kt + +fun foo(n: Number) { + if (when (n) { + is Float -> null + else -> 32 + } == null) { + } + if (when (n) { + is Float -> null + else -> 32 + } != null) { + } +} + +fun box() { + foo(2.0f) +} + +// EXPECTATIONS JVM_IR +// test.kt:18 box +// test.kt:5 foo +// test.kt:6 foo +// test.kt:5 foo +// test.kt:10 foo +// test.kt:11 foo +// test.kt:10 foo +// test.kt:15 foo +// test.kt:19 box + +// EXPECTATIONS JS_IR +// test.kt:18 box +// test.kt:6 foo +// test.kt:6 foo +// test.kt:11 foo +// test.kt:11 foo +// test.kt:15 foo +// test.kt:19 box diff --git a/compiler/testData/debug/stepping/whenInPrimitiveToObjectComparison.kt b/compiler/testData/debug/stepping/whenInPrimitiveToObjectComparison.kt new file mode 100644 index 00000000000..58fac447a5d --- /dev/null +++ b/compiler/testData/debug/stepping/whenInPrimitiveToObjectComparison.kt @@ -0,0 +1,41 @@ +// IGNORE_BACKEND: WASM +// FILE: test.kt + +fun foo(n: Any) { + if (1 == when (n) { + is Int -> n + else -> 1.0f + }) { + } + if (1 != when (n) { + is Int -> n + else -> 1.0f + }) { + } +} + +fun box() { + foo(2) +} + +// EXPECTATIONS JVM_IR +// test.kt:18 box +// test.kt:5 foo +// test.kt:6 foo +// test.kt:5 foo +// test.kt:10 foo +// test.kt:11 foo +// test.kt:10 foo +// test.kt:15 foo +// test.kt:19 box + +// EXPECTATIONS JS_IR +// test.kt:18 box +// test.kt:6 foo +// test.kt:6 foo +// test.kt:5 foo +// test.kt:11 foo +// test.kt:11 foo +// test.kt:10 foo +// test.kt:15 foo +// test.kt:19 box diff --git a/compiler/testData/debug/stepping/whenInZeroComparison.kt b/compiler/testData/debug/stepping/whenInZeroComparison.kt new file mode 100644 index 00000000000..fd41b05880a --- /dev/null +++ b/compiler/testData/debug/stepping/whenInZeroComparison.kt @@ -0,0 +1,29 @@ +// IGNORE_BACKEND: WASM +// FILE: test.kt + +fun foo(n: Number) { + if (when (n) { + is Float -> 1 + else -> 0 + } == 0) { + } +} + +fun box() { + foo(2.0f) +} + +// EXPECTATIONS JVM_IR +// test.kt:13 box +// test.kt:5 foo +// test.kt:6 foo +// test.kt:5 foo +// test.kt:10 foo +// test.kt:14 box + +// EXPECTATIONS JS_IR +// test.kt:13 box +// test.kt:6 foo +// test.kt:6 foo +// test.kt:10 foo +// test.kt:14 box diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrSteppingWithBytecodeInlinerTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrSteppingWithBytecodeInlinerTestGenerated.java index a69ab2012f9..1d153f08589 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrSteppingWithBytecodeInlinerTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrSteppingWithBytecodeInlinerTestGenerated.java @@ -601,6 +601,48 @@ public class IrSteppingWithBytecodeInlinerTestGenerated extends AbstractIrSteppi runTest("compiler/testData/debug/stepping/whenExpr.kt"); } + @Test + @TestMetadata("whenInConjunction.kt") + public void testWhenInConjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInConjunction.kt"); + } + + @Test + @TestMetadata("whenInDisjunction.kt") + public void testWhenInDisjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInDisjunction.kt"); + } + + @Test + @TestMetadata("whenInGeneralObjectComparison.kt") + public void testWhenInGeneralObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInGeneralObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInNegation.kt") + public void testWhenInNegation() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNegation.kt"); + } + + @Test + @TestMetadata("whenInNullComparison.kt") + public void testWhenInNullComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNullComparison.kt"); + } + + @Test + @TestMetadata("whenInPrimitiveToObjectComparison.kt") + public void testWhenInPrimitiveToObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInPrimitiveToObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInZeroComparison.kt") + public void testWhenInZeroComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInZeroComparison.kt"); + } + @Test @TestMetadata("whenIsChecks.kt") public void testWhenIsChecks() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrSteppingWithIrInlinerTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrSteppingWithIrInlinerTestGenerated.java index 93139bdb342..9dbbae82cff 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrSteppingWithIrInlinerTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrSteppingWithIrInlinerTestGenerated.java @@ -601,6 +601,48 @@ public class IrSteppingWithIrInlinerTestGenerated extends AbstractIrSteppingWith runTest("compiler/testData/debug/stepping/whenExpr.kt"); } + @Test + @TestMetadata("whenInConjunction.kt") + public void testWhenInConjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInConjunction.kt"); + } + + @Test + @TestMetadata("whenInDisjunction.kt") + public void testWhenInDisjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInDisjunction.kt"); + } + + @Test + @TestMetadata("whenInGeneralObjectComparison.kt") + public void testWhenInGeneralObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInGeneralObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInNegation.kt") + public void testWhenInNegation() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNegation.kt"); + } + + @Test + @TestMetadata("whenInNullComparison.kt") + public void testWhenInNullComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNullComparison.kt"); + } + + @Test + @TestMetadata("whenInPrimitiveToObjectComparison.kt") + public void testWhenInPrimitiveToObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInPrimitiveToObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInZeroComparison.kt") + public void testWhenInZeroComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInZeroComparison.kt"); + } + @Test @TestMetadata("whenIsChecks.kt") public void testWhenIsChecks() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsSteppingTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsSteppingTestGenerated.java index 06830f30d84..7c0df4700bc 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsSteppingTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrJsSteppingTestGenerated.java @@ -595,6 +595,48 @@ public class IrJsSteppingTestGenerated extends AbstractIrJsSteppingTest { runTest("compiler/testData/debug/stepping/whenExpr.kt"); } + @Test + @TestMetadata("whenInConjunction.kt") + public void testWhenInConjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInConjunction.kt"); + } + + @Test + @TestMetadata("whenInDisjunction.kt") + public void testWhenInDisjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInDisjunction.kt"); + } + + @Test + @TestMetadata("whenInGeneralObjectComparison.kt") + public void testWhenInGeneralObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInGeneralObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInNegation.kt") + public void testWhenInNegation() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNegation.kt"); + } + + @Test + @TestMetadata("whenInNullComparison.kt") + public void testWhenInNullComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNullComparison.kt"); + } + + @Test + @TestMetadata("whenInPrimitiveToObjectComparison.kt") + public void testWhenInPrimitiveToObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInPrimitiveToObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInZeroComparison.kt") + public void testWhenInZeroComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInZeroComparison.kt"); + } + @Test @TestMetadata("whenIsChecks.kt") public void testWhenIsChecks() throws Exception { diff --git a/plugins/kotlinx-serialization/testData/codegen/Basic.asm.fir.txt b/plugins/kotlinx-serialization/testData/codegen/Basic.asm.fir.txt index 93604f034c2..cf3e680eb2b 100644 --- a/plugins/kotlinx-serialization/testData/codegen/Basic.asm.fir.txt +++ b/plugins/kotlinx-serialization/testData/codegen/Basic.asm.fir.txt @@ -643,16 +643,16 @@ public final class OptionalUser : java/lang/Object { LDC () LDC () INVOKESPECIAL (User, , (Ljava/lang/String;Ljava/lang/String;)V) + LABEL (L4) + LINENUMBER (9) INVOKESTATIC (kotlin/jvm/internal/Intrinsics, areEqual, (Ljava/lang/Object;Ljava/lang/Object;)Z) - IFNE (L4) + IFNE (L5) ICONST_1 GOTO (L2) - LABEL (L4) + LABEL (L5) ICONST_0 LABEL (L2) - IFEQ (L5) - LABEL (L6) - LINENUMBER (9) + IFEQ (L6) ALOAD (1) ALOAD (2) ICONST_0 @@ -661,7 +661,7 @@ public final class OptionalUser : java/lang/Object { ALOAD (0) GETFIELD (OptionalUser, user, LUser;) INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeSerializableElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V) - LABEL (L5) + LABEL (L6) RETURN LABEL (L7) } diff --git a/plugins/kotlinx-serialization/testData/codegen/Basic.asm.ir.txt b/plugins/kotlinx-serialization/testData/codegen/Basic.asm.ir.txt index ad4401ed9d8..73a91dd5324 100644 --- a/plugins/kotlinx-serialization/testData/codegen/Basic.asm.ir.txt +++ b/plugins/kotlinx-serialization/testData/codegen/Basic.asm.ir.txt @@ -681,16 +681,16 @@ public final class OptionalUser : java/lang/Object { LDC () LDC () INVOKESPECIAL (User, , (Ljava/lang/String;Ljava/lang/String;)V) + LABEL (L4) + LINENUMBER (9) INVOKESTATIC (kotlin/jvm/internal/Intrinsics, areEqual, (Ljava/lang/Object;Ljava/lang/Object;)Z) - IFNE (L4) + IFNE (L5) ICONST_1 GOTO (L2) - LABEL (L4) + LABEL (L5) ICONST_0 LABEL (L2) - IFEQ (L5) - LABEL (L6) - LINENUMBER (9) + IFEQ (L6) ALOAD (1) ALOAD (2) ICONST_0 @@ -699,7 +699,7 @@ public final class OptionalUser : java/lang/Object { ALOAD (0) GETFIELD (OptionalUser, user, LUser;) INVOKEINTERFACE (kotlinx/serialization/encoding/CompositeEncoder, encodeSerializableElement, (Lkotlinx/serialization/descriptors/SerialDescriptor;ILkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V) - LABEL (L5) + LABEL (L6) RETURN LABEL (L7) } diff --git a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/FirWasmSteppingTestGenerated.java b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/FirWasmSteppingTestGenerated.java index 28cc520ec54..e8d25ec96b9 100644 --- a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/FirWasmSteppingTestGenerated.java +++ b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/FirWasmSteppingTestGenerated.java @@ -595,6 +595,48 @@ public class FirWasmSteppingTestGenerated extends AbstractFirWasmSteppingTest { runTest("compiler/testData/debug/stepping/whenExpr.kt"); } + @Test + @TestMetadata("whenInConjunction.kt") + public void testWhenInConjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInConjunction.kt"); + } + + @Test + @TestMetadata("whenInDisjunction.kt") + public void testWhenInDisjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInDisjunction.kt"); + } + + @Test + @TestMetadata("whenInGeneralObjectComparison.kt") + public void testWhenInGeneralObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInGeneralObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInNegation.kt") + public void testWhenInNegation() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNegation.kt"); + } + + @Test + @TestMetadata("whenInNullComparison.kt") + public void testWhenInNullComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNullComparison.kt"); + } + + @Test + @TestMetadata("whenInPrimitiveToObjectComparison.kt") + public void testWhenInPrimitiveToObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInPrimitiveToObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInZeroComparison.kt") + public void testWhenInZeroComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInZeroComparison.kt"); + } + @Test @TestMetadata("whenIsChecks.kt") public void testWhenIsChecks() throws Exception { diff --git a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/K1WasmSteppingTestGenerated.java b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/K1WasmSteppingTestGenerated.java index 7708a889533..f4c8e5f958a 100644 --- a/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/K1WasmSteppingTestGenerated.java +++ b/wasm/wasm.tests/tests-gen/org/jetbrains/kotlin/wasm/test/K1WasmSteppingTestGenerated.java @@ -595,6 +595,48 @@ public class K1WasmSteppingTestGenerated extends AbstractK1WasmSteppingTest { runTest("compiler/testData/debug/stepping/whenExpr.kt"); } + @Test + @TestMetadata("whenInConjunction.kt") + public void testWhenInConjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInConjunction.kt"); + } + + @Test + @TestMetadata("whenInDisjunction.kt") + public void testWhenInDisjunction() throws Exception { + runTest("compiler/testData/debug/stepping/whenInDisjunction.kt"); + } + + @Test + @TestMetadata("whenInGeneralObjectComparison.kt") + public void testWhenInGeneralObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInGeneralObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInNegation.kt") + public void testWhenInNegation() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNegation.kt"); + } + + @Test + @TestMetadata("whenInNullComparison.kt") + public void testWhenInNullComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInNullComparison.kt"); + } + + @Test + @TestMetadata("whenInPrimitiveToObjectComparison.kt") + public void testWhenInPrimitiveToObjectComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInPrimitiveToObjectComparison.kt"); + } + + @Test + @TestMetadata("whenInZeroComparison.kt") + public void testWhenInZeroComparison() throws Exception { + runTest("compiler/testData/debug/stepping/whenInZeroComparison.kt"); + } + @Test @TestMetadata("whenIsChecks.kt") public void testWhenIsChecks() throws Exception {