diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 2d8559e78b0..c601d759bd5 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -28097,6 +28097,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); } + @Test + @TestMetadata("smartCastOnBothEnds.kt") + public void testSmartCastOnBothEnds() throws Exception { + runTest("compiler/testData/codegen/box/ranges/contains/smartCastOnBothEnds.kt"); + } + @Test @TestMetadata("userDefinedContainsExtension.kt") public void testUserDefinedContainsExtension() throws Exception { 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 295785591a2..77d55ef14f8 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 @@ -13,6 +13,8 @@ import org.jetbrains.kotlin.backend.common.lower.loops.* import org.jetbrains.kotlin.backend.common.lower.loops.handlers.* import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase +import org.jetbrains.kotlin.builtins.PrimitiveType +import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.builders.andand import org.jetbrains.kotlin.ir.builders.irBlock @@ -29,6 +31,7 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.functions +import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.util.OperatorNameConventions @@ -361,26 +364,28 @@ private class Transformer( } private fun leastCommonPrimitiveNumericType(symbols: Symbols, t1: IrType, t2: IrType): IrType? { - val pt1 = t1.promoteIntegerTypeToIntIfRequired(symbols) - val pt2 = t2.promoteIntegerTypeToIntIfRequired(symbols) + val primitive1 = t1.getPrimitiveType() + val primitive2 = t2.getPrimitiveType() + val unsigned1 = t1.getUnsignedType() + val unsigned2 = t2.getUnsignedType() return when { - pt1.isDouble() || pt2.isDouble() -> symbols.double - pt1.isFloat() || pt2.isFloat() -> symbols.float - pt1.isULong() || pt2.isULong() -> symbols.uLong!! - pt1.isUInt() || pt2.isUInt() -> symbols.uInt!! - pt1.isLong() || pt2.isLong() -> symbols.long - pt1.isInt() || pt2.isInt() -> symbols.int - pt1.isChar() || pt2.isChar() -> symbols.char - else -> error("Unexpected types: t1=${t1.classOrNull?.owner?.name}, t2=${t2.classOrNull?.owner?.name}") + primitive1 == PrimitiveType.DOUBLE || primitive2 == PrimitiveType.DOUBLE -> symbols.double + primitive1 == PrimitiveType.FLOAT || primitive2 == PrimitiveType.FLOAT -> symbols.float + unsigned1 == UnsignedType.ULONG || unsigned2 == UnsignedType.ULONG -> symbols.uLong!! + unsigned1.isPromotableToUInt() || unsigned2.isPromotableToUInt() -> symbols.uInt!! + primitive1 == PrimitiveType.LONG || primitive2 == PrimitiveType.LONG -> symbols.long + primitive1.isPromotableToInt() || primitive2.isPromotableToInt() -> symbols.int + primitive1 == PrimitiveType.CHAR || primitive2 == PrimitiveType.CHAR -> symbols.char + else -> error("Unexpected types: t1=${t1.render()}, t2=${t2.render()}") }.defaultType } - private fun IrType.promoteIntegerTypeToIntIfRequired(symbols: Symbols): IrType = when { - isByte() || isShort() -> symbols.int.defaultType - isUByte() || isUShort() -> symbols.uInt!!.defaultType - else -> this - } + private fun PrimitiveType?.isPromotableToInt(): Boolean = + this == PrimitiveType.INT || this == PrimitiveType.SHORT || this == PrimitiveType.BYTE + + private fun UnsignedType?.isPromotableToUInt(): Boolean = + this == UnsignedType.UINT || this == UnsignedType.USHORT || this == UnsignedType.UBYTE } internal open class RangeHeaderInfoBuilder(context: CommonBackendContext, scopeOwnerSymbol: () -> IrSymbol) : diff --git a/compiler/testData/codegen/box/ranges/contains/smartCastOnBothEnds.kt b/compiler/testData/codegen/box/ranges/contains/smartCastOnBothEnds.kt new file mode 100644 index 00000000000..2f9ecb19b48 --- /dev/null +++ b/compiler/testData/codegen/box/ranges/contains/smartCastOnBothEnds.kt @@ -0,0 +1,32 @@ +// WITH_RUNTIME + +// Fails on the old JVM backend because of KT-42017. +// IGNORE_BACKEND: JVM + +fun checkDouble(a: Double?, b: Double?, c: Double): Boolean = a != null && b != null && c !in a..b +fun checkFloat(a: Float?, b: Float?, c: Float): Boolean = a != null && b != null && c !in a..b +fun checkLong(a: Long?, b: Long?, c: Long): Boolean = a != null && b != null && c !in a..b +fun checkInt(a: Int?, b: Int?, c: Int): Boolean = a != null && b != null && c !in a..b +fun checkChar(a: Char?, b: Char?, c: Char): Boolean = a != null && b != null && c !in a..b +fun checkByte(a: Byte?, b: Byte?, c: Byte): Boolean = a != null && b != null && c !in a..b +fun checkShort(a: Short?, b: Short?, c: Short): Boolean = a != null && b != null && c !in a..b +fun checkUInt(a: UInt?, b: UInt?, c: UInt): Boolean = a != null && b != null && c !in a..b +fun checkULong(a: ULong?, b: ULong?, c: ULong): Boolean = a != null && b != null && c !in a..b +fun checkUByte(a: UByte?, b: UByte?, c: UByte): Boolean = a != null && b != null && c !in a..b +fun checkUShort(a: UShort?, b: UShort?, c: UShort): Boolean = a != null && b != null && c !in a..b + +fun box(): String { + if (!checkDouble(1.0, 2.0, 0.0)) return "Fail Double" + if (!checkFloat(1.0f, 2.0f, 0.0f)) return "Fail Float" + if (!checkLong(1L, 2L, 0L)) return "Fail Long" + if (!checkInt(1, 2, 0)) return "Fail Int" + if (!checkChar('1', '2', '0')) return "Fail Char" + if (!checkByte(1.toByte(), 2.toByte(), 0.toByte())) return "Fail Byte" + if (!checkShort(1.toShort(), 2.toShort(), 0.toShort())) return "Fail Short" + if (!checkUInt(1u, 2u, 0u)) return "Fail UInt" + if (!checkULong(1UL, 2UL, 0UL)) return "Fail ULong" + if (!checkUByte(1u, 2u, 0u)) return "Fail UByte" + if (!checkUShort(1u, 2u, 0u)) return "Fail UShort" + + return "OK" +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index 014a21aa035..c35ca3e269b 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -28097,6 +28097,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); } + @Test + @TestMetadata("smartCastOnBothEnds.kt") + public void testSmartCastOnBothEnds() throws Exception { + runTest("compiler/testData/codegen/box/ranges/contains/smartCastOnBothEnds.kt"); + } + @Test @TestMetadata("userDefinedContainsExtension.kt") public void testUserDefinedContainsExtension() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 696bd580a87..f004c5693aa 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -28097,6 +28097,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); } + @Test + @TestMetadata("smartCastOnBothEnds.kt") + public void testSmartCastOnBothEnds() throws Exception { + runTest("compiler/testData/codegen/box/ranges/contains/smartCastOnBothEnds.kt"); + } + @Test @TestMetadata("userDefinedContainsExtension.kt") public void testUserDefinedContainsExtension() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index aba956d031c..12b0df6a3c5 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -23747,6 +23747,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public static class Contains extends AbstractLightAnalysisModeTest { + @TestMetadata("smartCastOnBothEnds.kt") + public void ignoreSmartCastOnBothEnds() throws Exception { + runTest("compiler/testData/codegen/box/ranges/contains/smartCastOnBothEnds.kt"); + } + private void runTest(String testDataFilePath) throws Exception { KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 6ab586f21df..e69f4de9409 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -19165,6 +19165,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); } + @TestMetadata("smartCastOnBothEnds.kt") + public void testSmartCastOnBothEnds() throws Exception { + runTest("compiler/testData/codegen/box/ranges/contains/smartCastOnBothEnds.kt"); + } + @TestMetadata("userDefinedContainsExtension.kt") public void testUserDefinedContainsExtension() throws Exception { runTest("compiler/testData/codegen/box/ranges/contains/userDefinedContainsExtension.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index a8e9f4711b9..2d958a7d0f8 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -18650,6 +18650,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); } + @TestMetadata("smartCastOnBothEnds.kt") + public void testSmartCastOnBothEnds() throws Exception { + runTest("compiler/testData/codegen/box/ranges/contains/smartCastOnBothEnds.kt"); + } + @TestMetadata("userDefinedContainsExtension.kt") public void testUserDefinedContainsExtension() throws Exception { runTest("compiler/testData/codegen/box/ranges/contains/userDefinedContainsExtension.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index c714d3a7bcc..4254f8bc012 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -18700,6 +18700,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); } + @TestMetadata("smartCastOnBothEnds.kt") + public void testSmartCastOnBothEnds() throws Exception { + runTest("compiler/testData/codegen/box/ranges/contains/smartCastOnBothEnds.kt"); + } + @TestMetadata("userDefinedContainsExtension.kt") public void testUserDefinedContainsExtension() throws Exception { runTest("compiler/testData/codegen/box/ranges/contains/userDefinedContainsExtension.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index 26bb2afc7c1..21e007c79d9 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -11937,6 +11937,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); } + @TestMetadata("smartCastOnBothEnds.kt") + public void testSmartCastOnBothEnds() throws Exception { + runTest("compiler/testData/codegen/box/ranges/contains/smartCastOnBothEnds.kt"); + } + @TestMetadata("userDefinedContainsExtension.kt") public void testUserDefinedContainsExtension() throws Exception { runTest("compiler/testData/codegen/box/ranges/contains/userDefinedContainsExtension.kt");