IR: support smart cast values in RangeContainsLowering

#KT-44878 Fixed
This commit is contained in:
Alexander Udalov
2021-02-19 22:17:29 +01:00
parent 820762ca16
commit acc2256de9
10 changed files with 95 additions and 15 deletions
@@ -28097,6 +28097,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); 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 @Test
@TestMetadata("userDefinedContainsExtension.kt") @TestMetadata("userDefinedContainsExtension.kt")
public void testUserDefinedContainsExtension() throws Exception { public void testUserDefinedContainsExtension() throws Exception {
@@ -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.loops.handlers.*
import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher import org.jetbrains.kotlin.backend.common.lower.matchers.SimpleCalleeMatcher
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase 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.IrStatement
import org.jetbrains.kotlin.ir.builders.andand import org.jetbrains.kotlin.ir.builders.andand
import org.jetbrains.kotlin.ir.builders.irBlock 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.types.*
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.functions 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.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -361,26 +364,28 @@ private class Transformer(
} }
private fun leastCommonPrimitiveNumericType(symbols: Symbols<CommonBackendContext>, t1: IrType, t2: IrType): IrType? { private fun leastCommonPrimitiveNumericType(symbols: Symbols<CommonBackendContext>, t1: IrType, t2: IrType): IrType? {
val pt1 = t1.promoteIntegerTypeToIntIfRequired(symbols) val primitive1 = t1.getPrimitiveType()
val pt2 = t2.promoteIntegerTypeToIntIfRequired(symbols) val primitive2 = t2.getPrimitiveType()
val unsigned1 = t1.getUnsignedType()
val unsigned2 = t2.getUnsignedType()
return when { return when {
pt1.isDouble() || pt2.isDouble() -> symbols.double primitive1 == PrimitiveType.DOUBLE || primitive2 == PrimitiveType.DOUBLE -> symbols.double
pt1.isFloat() || pt2.isFloat() -> symbols.float primitive1 == PrimitiveType.FLOAT || primitive2 == PrimitiveType.FLOAT -> symbols.float
pt1.isULong() || pt2.isULong() -> symbols.uLong!! unsigned1 == UnsignedType.ULONG || unsigned2 == UnsignedType.ULONG -> symbols.uLong!!
pt1.isUInt() || pt2.isUInt() -> symbols.uInt!! unsigned1.isPromotableToUInt() || unsigned2.isPromotableToUInt() -> symbols.uInt!!
pt1.isLong() || pt2.isLong() -> symbols.long primitive1 == PrimitiveType.LONG || primitive2 == PrimitiveType.LONG -> symbols.long
pt1.isInt() || pt2.isInt() -> symbols.int primitive1.isPromotableToInt() || primitive2.isPromotableToInt() -> symbols.int
pt1.isChar() || pt2.isChar() -> symbols.char primitive1 == PrimitiveType.CHAR || primitive2 == PrimitiveType.CHAR -> symbols.char
else -> error("Unexpected types: t1=${t1.classOrNull?.owner?.name}, t2=${t2.classOrNull?.owner?.name}") else -> error("Unexpected types: t1=${t1.render()}, t2=${t2.render()}")
}.defaultType }.defaultType
} }
private fun IrType.promoteIntegerTypeToIntIfRequired(symbols: Symbols<CommonBackendContext>): IrType = when { private fun PrimitiveType?.isPromotableToInt(): Boolean =
isByte() || isShort() -> symbols.int.defaultType this == PrimitiveType.INT || this == PrimitiveType.SHORT || this == PrimitiveType.BYTE
isUByte() || isUShort() -> symbols.uInt!!.defaultType
else -> this private fun UnsignedType?.isPromotableToUInt(): Boolean =
} this == UnsignedType.UINT || this == UnsignedType.USHORT || this == UnsignedType.UBYTE
} }
internal open class RangeHeaderInfoBuilder(context: CommonBackendContext, scopeOwnerSymbol: () -> IrSymbol) : internal open class RangeHeaderInfoBuilder(context: CommonBackendContext, scopeOwnerSymbol: () -> IrSymbol) :
@@ -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"
}
@@ -28097,6 +28097,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); 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 @Test
@TestMetadata("userDefinedContainsExtension.kt") @TestMetadata("userDefinedContainsExtension.kt")
public void testUserDefinedContainsExtension() throws Exception { public void testUserDefinedContainsExtension() throws Exception {
@@ -28097,6 +28097,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); 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 @Test
@TestMetadata("userDefinedContainsExtension.kt") @TestMetadata("userDefinedContainsExtension.kt")
public void testUserDefinedContainsExtension() throws Exception { public void testUserDefinedContainsExtension() throws Exception {
@@ -23747,6 +23747,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
public static class Contains extends AbstractLightAnalysisModeTest { 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 { private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath); KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
} }
@@ -19165,6 +19165,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); 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") @TestMetadata("userDefinedContainsExtension.kt")
public void testUserDefinedContainsExtension() throws Exception { public void testUserDefinedContainsExtension() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/userDefinedContainsExtension.kt"); runTest("compiler/testData/codegen/box/ranges/contains/userDefinedContainsExtension.kt");
@@ -18650,6 +18650,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); 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") @TestMetadata("userDefinedContainsExtension.kt")
public void testUserDefinedContainsExtension() throws Exception { public void testUserDefinedContainsExtension() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/userDefinedContainsExtension.kt"); runTest("compiler/testData/codegen/box/ranges/contains/userDefinedContainsExtension.kt");
@@ -18700,6 +18700,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); 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") @TestMetadata("userDefinedContainsExtension.kt")
public void testUserDefinedContainsExtension() throws Exception { public void testUserDefinedContainsExtension() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/userDefinedContainsExtension.kt"); runTest("compiler/testData/codegen/box/ranges/contains/userDefinedContainsExtension.kt");
@@ -11937,6 +11937,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/ranges/contains/rangeContainsString.kt"); 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") @TestMetadata("userDefinedContainsExtension.kt")
public void testUserDefinedContainsExtension() throws Exception { public void testUserDefinedContainsExtension() throws Exception {
runTest("compiler/testData/codegen/box/ranges/contains/userDefinedContainsExtension.kt"); runTest("compiler/testData/codegen/box/ranges/contains/userDefinedContainsExtension.kt");