diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java index 522ef5c5373..39c460b4e58 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/AsmUtil.java @@ -148,6 +148,10 @@ public class AsmUtil { return type == Type.INT_TYPE || type == Type.SHORT_TYPE || type == Type.BYTE_TYPE || type == Type.CHAR_TYPE; } + public static boolean isIntPrimitiveOrBoolean(Type type) { + return isIntPrimitive(type) || type == Type.BOOLEAN_TYPE; + } + public static boolean isNumberPrimitiveOrBoolean(Type type) { return isNumberPrimitive(type) || type.getSort() == Type.BOOLEAN; } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/BoxedVsPrimitiveBranchedValues.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/BoxedVsPrimitiveBranchedValues.kt index f288c8ed2d4..68e18c97b1e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/BoxedVsPrimitiveBranchedValues.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/BoxedVsPrimitiveBranchedValues.kt @@ -228,16 +228,85 @@ class BoxedToPrimitiveEquality private constructor( @JvmStatic fun isApplicable(opToken: IElementType, leftType: Type, rightType: Type) = - (opToken == KtTokens.EQEQ || - opToken == KtTokens.EXCLEQ - ) && - (rightType == Type.BOOLEAN_TYPE || - rightType == Type.CHAR_TYPE || - rightType == Type.BYTE_TYPE || - rightType == Type.SHORT_TYPE || - rightType == Type.INT_TYPE || - rightType == Type.LONG_TYPE - ) && + (opToken == KtTokens.EQEQ || opToken == KtTokens.EXCLEQ) && + AsmUtil.isIntPrimitiveOrBoolean(rightType) && AsmUtil.isBoxedTypeOf(leftType, rightType) } +} + + +class PrimitiveToBoxedEquality private constructor( + leftPrimitive: StackValue, + rightBoxed: StackValue, + primitiveType: Type +) : BranchedValue(leftPrimitive, rightBoxed, primitiveType, Opcodes.IFNE) { + private val primitiveType = leftPrimitive.type + private val boxedType = rightBoxed.type + + override fun patchOpcode(opcode: Int, v: InstructionAdapter): Int = + NumberCompare.patchOpcode(opcode, v, KtTokens.EQEQ, operandType) + + override fun condJump(jumpLabel: Label, v: InstructionAdapter, jumpIfFalse: Boolean) { + if (jumpIfFalse) { + jumpIfFalse(v, jumpLabel) + } + else { + jumpIfTrue(v, jumpLabel) + } + } + + private fun jumpIfFalse(v: InstructionAdapter, jumpLabel: Label) { + val notNullLabel = Label() + + arg1.put(primitiveType, v) + arg2!!.put(boxedType, v) + AsmUtil.dup(v, boxedType) + v.ifnonnull(notNullLabel) + + AsmUtil.pop(v, boxedType) + AsmUtil.pop(v, primitiveType) + v.goTo(jumpLabel) + + v.mark(notNullLabel) + coerce(boxedType, primitiveType, v) + v.visitJumpInsn(patchOpcode(opcode, v), jumpLabel) + } + + private fun jumpIfTrue(v: InstructionAdapter, jumpLabel: Label) { + val notNullLabel = Label() + val endLabel = Label() + + arg1.put(primitiveType, v) + arg2!!.put(boxedType, v) + AsmUtil.dup(v, boxedType) + v.ifnonnull(notNullLabel) + + AsmUtil.pop(v, boxedType) + AsmUtil.pop(v, primitiveType) + v.goTo(endLabel) + + v.mark(notNullLabel) + coerce(boxedType, primitiveType, v) + v.visitJumpInsn(patchOpcode(negatedOperations[opcode]!!, v), jumpLabel) + + v.mark(endLabel) + } + + companion object { + @JvmStatic + fun create(opToken: IElementType, left: StackValue, leftType: Type, right: StackValue, rightType: Type): BranchedValue = + if (!isApplicable(opToken, leftType, rightType)) + throw IllegalArgumentException("Not applicable for $opToken, $leftType, $rightType") + else when (opToken) { + KtTokens.EQEQ -> PrimitiveToBoxedEquality(left, right, leftType) + KtTokens.EXCLEQ -> Invert(PrimitiveToBoxedEquality(left, right, leftType)) + else -> throw AssertionError("Unexpected opToken: $opToken") + } + + @JvmStatic + fun isApplicable(opToken: IElementType, leftType: Type, rightType: Type) = + (opToken == KtTokens.EQEQ || opToken == KtTokens.EXCLEQ) && + AsmUtil.isIntPrimitiveOrBoolean(rightType) && + AsmUtil.isBoxedTypeOf(rightType, leftType) + } } \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 8ce28315537..887453e5044 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2899,6 +2899,11 @@ public class ExpressionCodegen extends KtVisitor impleme return BoxedToPrimitiveEquality.create(opToken, genLazy(left, leftType), leftType, genLazy(right, rightType), rightType); } + if (PrimitiveToBoxedEquality.isApplicable(opToken, leftType, rightType)) { + return BoxedToPrimitiveEquality.create(opToken, genLazy(left, leftType), leftType, genLazy(right, rightType), rightType); + } + + if (isPrimitive(leftType) != isPrimitive(rightType)) { leftType = boxType(leftType); rightType = boxType(rightType); diff --git a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveBoolean.kt b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveBoolean.kt index 72a0c220446..a4c037d5d19 100644 --- a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveBoolean.kt +++ b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveBoolean.kt @@ -28,14 +28,20 @@ fun box(): String { ax == false -> "Fail 13" !(ax == true) -> "Fail 14" !(ax != false) -> "Fail 15" - ax != bx -> "Fail 16" - ax == by -> "Fail 17" - !(ax == bx) -> "Fail 18" - !(ax != by) -> "Fail 19" - an == true -> "Fail 20" - !(an != true) -> "Fail 21" - an == bx -> "Fail 22" - !(an != bx) -> "Fail 23" + ax != x -> "Fail 16" + ax == y -> "Fail 17" + !(ax == x) -> "Fail 18" + !(ax != y) -> "Fail 19" + ax != bx -> "Fail 20" + ax == by -> "Fail 21" + !(ax == bx) -> "Fail 22" + !(ax != by) -> "Fail 23" + an == true -> "Fail 24" + !(an != true) -> "Fail 25" + an == x -> "Fail 26" + !(an != x) -> "Fail 27" + an == bx -> "Fail 28" + !(an != bx) -> "Fail 29" else -> "OK" } } diff --git a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveByte.kt b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveByte.kt index 9468ddc5587..327054de5dd 100644 --- a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveByte.kt +++ b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveByte.kt @@ -28,14 +28,20 @@ fun box(): String { ax == 1.toByte() -> "Fail 13" !(ax == 0.toByte()) -> "Fail 14" !(ax != 1.toByte()) -> "Fail 15" - ax != bx -> "Fail 16" - ax == by -> "Fail 17" - !(ax == bx) -> "Fail 18" - !(ax != by) -> "Fail 19" - an == 0.toByte() -> "Fail 20" - !(an != 0.toByte()) -> "Fail 21" - an == bx -> "Fail 22" - !(an != bx) -> "Fail 23" + ax != x -> "Fail 16" + ax == y -> "Fail 17" + !(ax == x) -> "Fail 18" + !(ax != y) -> "Fail 19" + ax != bx -> "Fail 20" + ax == by -> "Fail 21" + !(ax == bx) -> "Fail 22" + !(ax != by) -> "Fail 23" + an == 0.toByte() -> "Fail 24" + !(an != 0.toByte()) -> "Fail 25" + an == x -> "Fail 26" + !(an != x) -> "Fail 27" + an == bx -> "Fail 28" + !(an != bx) -> "Fail 29" else -> "OK" } } diff --git a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveChar.kt b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveChar.kt index 56ce7b08a07..589fe0b563f 100644 --- a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveChar.kt +++ b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveChar.kt @@ -28,14 +28,20 @@ fun box(): String { ax == '1' -> "Fail 13" !(ax == '0') -> "Fail 14" !(ax != '1') -> "Fail 15" - ax != bx -> "Fail 16" - ax == by -> "Fail 17" - !(ax == bx) -> "Fail 18" - !(ax != by) -> "Fail 19" - an == '0' -> "Fail 20" - !(an != '0') -> "Fail 21" - an == bx -> "Fail 22" - !(an != bx) -> "Fail 23" + ax != x -> "Fail 16" + ax == y -> "Fail 17" + !(ax == x) -> "Fail 18" + !(ax != y) -> "Fail 19" + ax != bx -> "Fail 20" + ax == by -> "Fail 21" + !(ax == bx) -> "Fail 22" + !(ax != by) -> "Fail 23" + an == '0' -> "Fail 24" + !(an != '0') -> "Fail 25" + an == x -> "Fail 26" + !(an != x) -> "Fail 27" + an == bx -> "Fail 28" + !(an != bx) -> "Fail 29" else -> "OK" } } diff --git a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveInt.kt b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveInt.kt index d925bec40d6..8b816d0b70b 100644 --- a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveInt.kt +++ b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveInt.kt @@ -28,14 +28,20 @@ fun box(): String { ax == 1 -> "Fail 13" !(ax == 0) -> "Fail 14" !(ax != 1) -> "Fail 15" - ax != bx -> "Fail 16" - ax == by -> "Fail 17" - !(ax == bx) -> "Fail 18" - !(ax != by) -> "Fail 19" - an == 0 -> "Fail 20" - !(an != 0) -> "Fail 21" - an == bx -> "Fail 22" - !(an != bx) -> "Fail 23" + ax != x -> "Fail 16" + ax == y -> "Fail 17" + !(ax == x) -> "Fail 18" + !(ax != y) -> "Fail 19" + ax != bx -> "Fail 20" + ax == by -> "Fail 21" + !(ax == bx) -> "Fail 22" + !(ax != by) -> "Fail 23" + an == 0 -> "Fail 24" + !(an != 0) -> "Fail 25" + an == x -> "Fail 26" + !(an != x) -> "Fail 27" + an == bx -> "Fail 28" + !(an != bx) -> "Fail 29" else -> "OK" } } diff --git a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveLong.kt b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveLong.kt index 1b4cbf0132d..57253df6725 100644 --- a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveLong.kt +++ b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveLong.kt @@ -28,14 +28,20 @@ fun box(): String { ax == 1L -> "Fail 13" !(ax == 0L) -> "Fail 14" !(ax != 1L) -> "Fail 15" - ax != bx -> "Fail 16" - ax == by -> "Fail 17" - !(ax == bx) -> "Fail 18" - !(ax != by) -> "Fail 19" - an == 0L -> "Fail 20" - !(an != 0L) -> "Fail 21" - an == bx -> "Fail 22" - !(an != bx) -> "Fail 23" + ax != x -> "Fail 16" + ax == y -> "Fail 17" + !(ax == x) -> "Fail 18" + !(ax != y) -> "Fail 19" + ax != bx -> "Fail 20" + ax == by -> "Fail 21" + !(ax == bx) -> "Fail 22" + !(ax != by) -> "Fail 23" + an == 0L -> "Fail 24" + !(an != 0L) -> "Fail 25" + an == x -> "Fail 26" + !(an != x) -> "Fail 27" + an == bx -> "Fail 28" + !(an != bx) -> "Fail 29" else -> "OK" } } diff --git a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveShort.kt b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveShort.kt index 0cd794cfb38..e93839a29c1 100644 --- a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveShort.kt +++ b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveShort.kt @@ -28,14 +28,20 @@ fun box(): String { ax == 1.toShort() -> "Fail 13" !(ax == 0.toShort()) -> "Fail 14" !(ax != 1.toShort()) -> "Fail 15" - ax != bx -> "Fail 16" - ax == by -> "Fail 17" - !(ax == bx) -> "Fail 18" - !(ax != by) -> "Fail 19" - an == 0.toShort() -> "Fail 20" - !(an != 0.toShort()) -> "Fail 21" - an == bx -> "Fail 22" - !(an != bx) -> "Fail 23" + ax != x -> "Fail 16" + ax == y -> "Fail 17" + !(ax == x) -> "Fail 18" + !(ax != y) -> "Fail 19" + ax != bx -> "Fail 20" + ax == by -> "Fail 21" + !(ax == bx) -> "Fail 22" + !(ax != by) -> "Fail 23" + an == 0.toShort() -> "Fail 24" + !(an != 0.toShort()) -> "Fail 25" + an == x -> "Fail 26" + !(an != x) -> "Fail 27" + an == bx -> "Fail 28" + !(an != bx) -> "Fail 29" else -> "OK" } } diff --git a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedBoolean.kt b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedBoolean.kt new file mode 100644 index 00000000000..a80c77136ad --- /dev/null +++ b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedBoolean.kt @@ -0,0 +1,47 @@ +// Auto-generated by GeneratePrimitiveVsObjectEqualityTestData. Do not edit! + +val nx: Boolean? = true +val nn: Boolean? = null +val x: Boolean = true +val y: Boolean = false + +fun box(): String { + val ax: Boolean? = true + val an: Boolean? = null + val bx: Boolean = true + val by: Boolean = false + + return when { + true != nx -> "Fail 0" + false == nx -> "Fail 1" + !(true == nx) -> "Fail 2" + !(false != nx) -> "Fail 3" + x != nx -> "Fail 4" + y == nx -> "Fail 5" + !(x == nx) -> "Fail 6" + !(y != nx) -> "Fail 7" + true == nn -> "Fail 8" + !(true != nn) -> "Fail 9" + x == nn -> "Fail 10" + !(x != nn) -> "Fail 11" + true != ax -> "Fail 12" + false == ax -> "Fail 13" + !(true == ax) -> "Fail 14" + !(false != ax) -> "Fail 15" + x != ax -> "Fail 16" + y == ax -> "Fail 17" + !(x == ax) -> "Fail 18" + !(y != ax) -> "Fail 19" + bx != ax -> "Fail 20" + by == ax -> "Fail 21" + !(bx == ax) -> "Fail 22" + !(by != ax) -> "Fail 23" + true == an -> "Fail 24" + !(true != an) -> "Fail 25" + x == an -> "Fail 26" + !(x != an) -> "Fail 27" + bx == an -> "Fail 28" + !(bx != an) -> "Fail 29" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedByte.kt b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedByte.kt new file mode 100644 index 00000000000..937d82722fa --- /dev/null +++ b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedByte.kt @@ -0,0 +1,47 @@ +// Auto-generated by GeneratePrimitiveVsObjectEqualityTestData. Do not edit! + +val nx: Byte? = 0.toByte() +val nn: Byte? = null +val x: Byte = 0.toByte() +val y: Byte = 1.toByte() + +fun box(): String { + val ax: Byte? = 0.toByte() + val an: Byte? = null + val bx: Byte = 0.toByte() + val by: Byte = 1.toByte() + + return when { + 0.toByte() != nx -> "Fail 0" + 1.toByte() == nx -> "Fail 1" + !(0.toByte() == nx) -> "Fail 2" + !(1.toByte() != nx) -> "Fail 3" + x != nx -> "Fail 4" + y == nx -> "Fail 5" + !(x == nx) -> "Fail 6" + !(y != nx) -> "Fail 7" + 0.toByte() == nn -> "Fail 8" + !(0.toByte() != nn) -> "Fail 9" + x == nn -> "Fail 10" + !(x != nn) -> "Fail 11" + 0.toByte() != ax -> "Fail 12" + 1.toByte() == ax -> "Fail 13" + !(0.toByte() == ax) -> "Fail 14" + !(1.toByte() != ax) -> "Fail 15" + x != ax -> "Fail 16" + y == ax -> "Fail 17" + !(x == ax) -> "Fail 18" + !(y != ax) -> "Fail 19" + bx != ax -> "Fail 20" + by == ax -> "Fail 21" + !(bx == ax) -> "Fail 22" + !(by != ax) -> "Fail 23" + 0.toByte() == an -> "Fail 24" + !(0.toByte() != an) -> "Fail 25" + x == an -> "Fail 26" + !(x != an) -> "Fail 27" + bx == an -> "Fail 28" + !(bx != an) -> "Fail 29" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedChar.kt b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedChar.kt new file mode 100644 index 00000000000..331ab442988 --- /dev/null +++ b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedChar.kt @@ -0,0 +1,47 @@ +// Auto-generated by GeneratePrimitiveVsObjectEqualityTestData. Do not edit! + +val nx: Char? = '0' +val nn: Char? = null +val x: Char = '0' +val y: Char = '1' + +fun box(): String { + val ax: Char? = '0' + val an: Char? = null + val bx: Char = '0' + val by: Char = '1' + + return when { + '0' != nx -> "Fail 0" + '1' == nx -> "Fail 1" + !('0' == nx) -> "Fail 2" + !('1' != nx) -> "Fail 3" + x != nx -> "Fail 4" + y == nx -> "Fail 5" + !(x == nx) -> "Fail 6" + !(y != nx) -> "Fail 7" + '0' == nn -> "Fail 8" + !('0' != nn) -> "Fail 9" + x == nn -> "Fail 10" + !(x != nn) -> "Fail 11" + '0' != ax -> "Fail 12" + '1' == ax -> "Fail 13" + !('0' == ax) -> "Fail 14" + !('1' != ax) -> "Fail 15" + x != ax -> "Fail 16" + y == ax -> "Fail 17" + !(x == ax) -> "Fail 18" + !(y != ax) -> "Fail 19" + bx != ax -> "Fail 20" + by == ax -> "Fail 21" + !(bx == ax) -> "Fail 22" + !(by != ax) -> "Fail 23" + '0' == an -> "Fail 24" + !('0' != an) -> "Fail 25" + x == an -> "Fail 26" + !(x != an) -> "Fail 27" + bx == an -> "Fail 28" + !(bx != an) -> "Fail 29" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedInt.kt b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedInt.kt new file mode 100644 index 00000000000..a9e3946fa90 --- /dev/null +++ b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedInt.kt @@ -0,0 +1,47 @@ +// Auto-generated by GeneratePrimitiveVsObjectEqualityTestData. Do not edit! + +val nx: Int? = 0 +val nn: Int? = null +val x: Int = 0 +val y: Int = 1 + +fun box(): String { + val ax: Int? = 0 + val an: Int? = null + val bx: Int = 0 + val by: Int = 1 + + return when { + 0 != nx -> "Fail 0" + 1 == nx -> "Fail 1" + !(0 == nx) -> "Fail 2" + !(1 != nx) -> "Fail 3" + x != nx -> "Fail 4" + y == nx -> "Fail 5" + !(x == nx) -> "Fail 6" + !(y != nx) -> "Fail 7" + 0 == nn -> "Fail 8" + !(0 != nn) -> "Fail 9" + x == nn -> "Fail 10" + !(x != nn) -> "Fail 11" + 0 != ax -> "Fail 12" + 1 == ax -> "Fail 13" + !(0 == ax) -> "Fail 14" + !(1 != ax) -> "Fail 15" + x != ax -> "Fail 16" + y == ax -> "Fail 17" + !(x == ax) -> "Fail 18" + !(y != ax) -> "Fail 19" + bx != ax -> "Fail 20" + by == ax -> "Fail 21" + !(bx == ax) -> "Fail 22" + !(by != ax) -> "Fail 23" + 0 == an -> "Fail 24" + !(0 != an) -> "Fail 25" + x == an -> "Fail 26" + !(x != an) -> "Fail 27" + bx == an -> "Fail 28" + !(bx != an) -> "Fail 29" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedLong.kt b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedLong.kt new file mode 100644 index 00000000000..e2eccb0ddf5 --- /dev/null +++ b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedLong.kt @@ -0,0 +1,47 @@ +// Auto-generated by GeneratePrimitiveVsObjectEqualityTestData. Do not edit! + +val nx: Long? = 0L +val nn: Long? = null +val x: Long = 0L +val y: Long = 1L + +fun box(): String { + val ax: Long? = 0L + val an: Long? = null + val bx: Long = 0L + val by: Long = 1L + + return when { + 0L != nx -> "Fail 0" + 1L == nx -> "Fail 1" + !(0L == nx) -> "Fail 2" + !(1L != nx) -> "Fail 3" + x != nx -> "Fail 4" + y == nx -> "Fail 5" + !(x == nx) -> "Fail 6" + !(y != nx) -> "Fail 7" + 0L == nn -> "Fail 8" + !(0L != nn) -> "Fail 9" + x == nn -> "Fail 10" + !(x != nn) -> "Fail 11" + 0L != ax -> "Fail 12" + 1L == ax -> "Fail 13" + !(0L == ax) -> "Fail 14" + !(1L != ax) -> "Fail 15" + x != ax -> "Fail 16" + y == ax -> "Fail 17" + !(x == ax) -> "Fail 18" + !(y != ax) -> "Fail 19" + bx != ax -> "Fail 20" + by == ax -> "Fail 21" + !(bx == ax) -> "Fail 22" + !(by != ax) -> "Fail 23" + 0L == an -> "Fail 24" + !(0L != an) -> "Fail 25" + x == an -> "Fail 26" + !(x != an) -> "Fail 27" + bx == an -> "Fail 28" + !(bx != an) -> "Fail 29" + else -> "OK" + } +} diff --git a/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedShort.kt b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedShort.kt new file mode 100644 index 00000000000..29bf73f855a --- /dev/null +++ b/compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedShort.kt @@ -0,0 +1,47 @@ +// Auto-generated by GeneratePrimitiveVsObjectEqualityTestData. Do not edit! + +val nx: Short? = 0.toShort() +val nn: Short? = null +val x: Short = 0.toShort() +val y: Short = 1.toShort() + +fun box(): String { + val ax: Short? = 0.toShort() + val an: Short? = null + val bx: Short = 0.toShort() + val by: Short = 1.toShort() + + return when { + 0.toShort() != nx -> "Fail 0" + 1.toShort() == nx -> "Fail 1" + !(0.toShort() == nx) -> "Fail 2" + !(1.toShort() != nx) -> "Fail 3" + x != nx -> "Fail 4" + y == nx -> "Fail 5" + !(x == nx) -> "Fail 6" + !(y != nx) -> "Fail 7" + 0.toShort() == nn -> "Fail 8" + !(0.toShort() != nn) -> "Fail 9" + x == nn -> "Fail 10" + !(x != nn) -> "Fail 11" + 0.toShort() != ax -> "Fail 12" + 1.toShort() == ax -> "Fail 13" + !(0.toShort() == ax) -> "Fail 14" + !(1.toShort() != ax) -> "Fail 15" + x != ax -> "Fail 16" + y == ax -> "Fail 17" + !(x == ax) -> "Fail 18" + !(y != ax) -> "Fail 19" + bx != ax -> "Fail 20" + by == ax -> "Fail 21" + !(bx == ax) -> "Fail 22" + !(by != ax) -> "Fail 23" + 0.toShort() == an -> "Fail 24" + !(0.toShort() != an) -> "Fail 25" + x == an -> "Fail 26" + !(x != an) -> "Fail 27" + bx == an -> "Fail 28" + !(bx != an) -> "Fail 29" + else -> "OK" + } +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index af4075c5bbe..010cf86b9cf 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -12557,6 +12557,42 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveShort.kt"); doTest(fileName); } + + @TestMetadata("primitiveEqBoxedBoolean.kt") + public void testPrimitiveEqBoxedBoolean() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedBoolean.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedByte.kt") + public void testPrimitiveEqBoxedByte() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedByte.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedChar.kt") + public void testPrimitiveEqBoxedChar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedChar.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedInt.kt") + public void testPrimitiveEqBoxedInt() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedInt.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedLong.kt") + public void testPrimitiveEqBoxedLong() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedLong.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedShort.kt") + public void testPrimitiveEqBoxedShort() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedShort.kt"); + doTest(fileName); + } } } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index d6d04a31ab5..3c2c1877834 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -12557,6 +12557,42 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveShort.kt"); doTest(fileName); } + + @TestMetadata("primitiveEqBoxedBoolean.kt") + public void testPrimitiveEqBoxedBoolean() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedBoolean.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedByte.kt") + public void testPrimitiveEqBoxedByte() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedByte.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedChar.kt") + public void testPrimitiveEqBoxedChar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedChar.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedInt.kt") + public void testPrimitiveEqBoxedInt() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedInt.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedLong.kt") + public void testPrimitiveEqBoxedLong() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedLong.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedShort.kt") + public void testPrimitiveEqBoxedShort() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedShort.kt"); + doTest(fileName); + } } } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 90eb0eed634..83833bb68e1 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -12557,6 +12557,42 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveShort.kt"); doTest(fileName); } + + @TestMetadata("primitiveEqBoxedBoolean.kt") + public void testPrimitiveEqBoxedBoolean() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedBoolean.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedByte.kt") + public void testPrimitiveEqBoxedByte() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedByte.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedChar.kt") + public void testPrimitiveEqBoxedChar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedChar.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedInt.kt") + public void testPrimitiveEqBoxedInt() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedInt.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedLong.kt") + public void testPrimitiveEqBoxedLong() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedLong.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedShort.kt") + public void testPrimitiveEqBoxedShort() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedShort.kt"); + doTest(fileName); + } } } } diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GeneratePrimitiveVsObjectEqualityTestData.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GeneratePrimitiveVsObjectEqualityTestData.kt index 86574ca87b5..fb426f11aaa 100644 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GeneratePrimitiveVsObjectEqualityTestData.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GeneratePrimitiveVsObjectEqualityTestData.kt @@ -35,54 +35,117 @@ object GeneratePrimitiveVsObjectEqualityTestData { private fun PrintWriter.generateBoxedVsPrimitiveTestBody(type: String, x: String, y: String) { println("// $PREAMBLE_MESSAGE") println() - println("val nx: $type? = $x") - println("val nn: $type? = null") - println("val x: $type = $x") - println("val y: $type = $y") + generateGlobalVals(type, x, y) println() println("fun box(): String {") - println(" val ax: $type? = $x") - println(" val an: $type? = null") - println(" val bx: $type = $x") - println(" val by: $type = $y") + generateLocalVals(type, x, y) println() println(" return when {") - listOf( - "nx != $x", - "nx == $y", - "!(nx == $x)", - "!(nx != $y)", - "nx != x", - "nx == y", - "!(nx == x)", - "!(nx != y)", - "nn == $x", - "!(nn != $x)", - "nn == x", - "!(nn != x)", - "ax != $x", - "ax == $y", - "!(ax == $x)", - "!(ax != $y)", - "ax != bx", - "ax == by", - "!(ax == bx)", - "!(ax != by)", - "an == $x", - "!(an != $x)", - "an == bx", - "!(an != bx)" - ).forEachIndexed { i, condition -> - println(" $condition -> \"Fail $i\"") - } + generateFailureClauses( + *failuresForEqualAndUnequalLeft("nx", x, y), + *failuresForEqualAndUnequalLeft("nx", "x", "y"), + *failuresForUnequalLeft("nn", x), + *failuresForUnequalLeft("nn", "x"), + *failuresForEqualAndUnequalLeft("ax", x, y), + *failuresForEqualAndUnequalLeft("ax", "x", "y"), + *failuresForEqualAndUnequalLeft("ax", "bx", "by"), + *failuresForUnequalLeft("an", x), + *failuresForUnequalLeft("an", "x"), + *failuresForUnequalLeft("an", "bx") + ) println(" else -> \"OK\"") println(" }") println("}") } + private fun failuresForEqualAndUnequalLeft(lhs: String, equalRhs: String, unequalRhs: String) = + arrayOf( + "$lhs != $equalRhs", + "$lhs == $unequalRhs", + "!($lhs == $equalRhs)", + "!($lhs != $unequalRhs)" + ) + + private fun failuresForUnequalLeft(lhs: String, unequalRhs: String) = + arrayOf( + "$lhs == $unequalRhs", + "!($lhs != $unequalRhs)" + ) + + private fun PrintWriter.generateLocalVals(type: String, x: String, y: String) { + println(" val ax: $type? = $x") + println(" val an: $type? = null") + println(" val bx: $type = $x") + println(" val by: $type = $y") + } + + private fun PrintWriter.generateGlobalVals(type: String, x: String, y: String) { + println("val nx: $type? = $x") + println("val nn: $type? = null") + println("val x: $type = $x") + println("val y: $type = $y") + } + + private fun PrintWriter.generateFailureClauses(vararg failures: String) { + failures.forEachIndexed { i, condition -> + println(" $condition -> \"Fail $i\"") + } + } + + private fun generatePrimitiveVsBoxedTest(type: String, x: String, y: String) { + PrintWriter(File(GENERATED_DIR, "primitiveEqBoxed$type.kt")).use { + it.generatePrimitiveVsBoxedTestBody(type, x, y) + } + } + + private fun PrintWriter.generatePrimitiveVsBoxedTestBody(type: String, x: String, y: String) { + println("// $PREAMBLE_MESSAGE") + println() + + generateGlobalVals(type, x, y) + println() + println("fun box(): String {") + generateLocalVals(type, x, y) + println() + + println(" return when {") + + generateFailureClauses( + *failuresForEqualAndUnequalRight(x, y, "nx"), + *failuresForEqualAndUnequalRight("x", "y", "nx"), + *failuresForUnequalRight(x, "nn"), + *failuresForUnequalRight("x", "nn"), + *failuresForEqualAndUnequalRight(x, y, "ax"), + *failuresForEqualAndUnequalRight("x", "y", "ax"), + *failuresForEqualAndUnequalRight("bx", "by", "ax"), + *failuresForUnequalRight(x, "an"), + *failuresForUnequalRight("x", "an"), + *failuresForUnequalRight("bx", "an") + ) + + println(" else -> \"OK\"") + println(" }") + println("}") + } + + private fun failuresForEqualAndUnequalRight(equalLhs: String, unequalLhs: String, rhs: String) = + arrayOf( + "$equalLhs != $rhs", + "$unequalLhs == $rhs", + "!($equalLhs == $rhs)", + "!($unequalLhs != $rhs)" + ) + + private fun failuresForUnequalRight(unequalLhs: String, rhs: String) = + arrayOf( + "$unequalLhs == $rhs", + "!($unequalLhs != $rhs)" + ) + + @JvmStatic fun main(args: Array) { if (!TEST_DATA_DIR.exists()) throw AssertionError("${TEST_DATA_DIR.path} doesn't exist") @@ -96,5 +159,12 @@ object GeneratePrimitiveVsObjectEqualityTestData { generateBoxedVsPrimitiveTest("Short", "0.toShort()", "1.toShort()") generateBoxedVsPrimitiveTest("Int", "0", "1") generateBoxedVsPrimitiveTest("Long", "0L", "1L") + + generatePrimitiveVsBoxedTest("Boolean", "true", "false") + generatePrimitiveVsBoxedTest("Char", "'0'", "'1'") + generatePrimitiveVsBoxedTest("Byte", "0.toByte()", "1.toByte()") + generatePrimitiveVsBoxedTest("Short", "0.toShort()", "1.toShort()") + generatePrimitiveVsBoxedTest("Int", "0", "1") + generatePrimitiveVsBoxedTest("Long", "0L", "1L") } } \ No newline at end of file diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 8a208bb2bb8..aa35eee981b 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -14015,6 +14015,42 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/boxedEqPrimitiveShort.kt"); doTest(fileName); } + + @TestMetadata("primitiveEqBoxedBoolean.kt") + public void testPrimitiveEqBoxedBoolean() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedBoolean.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedByte.kt") + public void testPrimitiveEqBoxedByte() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedByte.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedChar.kt") + public void testPrimitiveEqBoxedChar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedChar.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedInt.kt") + public void testPrimitiveEqBoxedInt() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedInt.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedLong.kt") + public void testPrimitiveEqBoxedLong() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedLong.kt"); + doTest(fileName); + } + + @TestMetadata("primitiveEqBoxedShort.kt") + public void testPrimitiveEqBoxedShort() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/primitiveTypes/equalityWithNullable/generated/primitiveEqBoxedShort.kt"); + doTest(fileName); + } } } }