Intrinsify some mismatching range/element combinations for in/in!
It's safe to upcast integer types to Long,
floating-point types to Double.
So we don't have to create a range instance for cases such as
fun testLongInInt(x: Long, a: Int, b: Int) =
x in a .. b
which is equivalent to
fun testLongInInt(x: Long, a: Int, b: Int) =
x in a.toLong() .. b.toLong()
This commit is contained in:
@@ -174,26 +174,28 @@ fun isPrimitiveRangeContains(descriptor: CallableDescriptor): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
fun isIntPrimitiveRangeExtensionForInt(descriptor: CallableDescriptor): Boolean {
|
||||
fun isPrimitiveNumberRangeExtensionContainsPrimitiveNumber(descriptor: CallableDescriptor): Boolean {
|
||||
if (descriptor.name.asString() != "contains") return false
|
||||
|
||||
val extensionReceiverType = descriptor.extensionReceiverParameter?.type ?: return false
|
||||
val extensionReceiverClassDescriptor = extensionReceiverType.constructor.declarationDescriptor as? ClassDescriptor ?: return false
|
||||
if (!isTopLevelInPackage(extensionReceiverClassDescriptor, "ClosedRange", "kotlin.ranges")) return false
|
||||
|
||||
val rangeElementType = extensionReceiverType.arguments.singleOrNull()?.type ?: return false
|
||||
if (!isIntPrimitiveType(rangeElementType)) return false
|
||||
val rangeElementType = getRangeOrProgressionElementType(extensionReceiverType) ?: return false
|
||||
if (!isPrimitiveNumberType(rangeElementType)) return false
|
||||
|
||||
val argumentType = descriptor.valueParameters.singleOrNull()?.type ?: return false
|
||||
if (!isIntPrimitiveType(argumentType)) return false
|
||||
if (!isPrimitiveNumberType(argumentType)) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isIntPrimitiveType(type: KotlinType) =
|
||||
private fun isPrimitiveNumberType(type: KotlinType) =
|
||||
KotlinBuiltIns.isByte(type) ||
|
||||
KotlinBuiltIns.isShort(type) ||
|
||||
KotlinBuiltIns.isInt(type)
|
||||
KotlinBuiltIns.isInt(type) ||
|
||||
KotlinBuiltIns.isChar(type) ||
|
||||
KotlinBuiltIns.isLong(type) ||
|
||||
KotlinBuiltIns.isFloat(type) ||
|
||||
KotlinBuiltIns.isDouble(type)
|
||||
|
||||
fun isClosedFloatingPointRangeContains(descriptor: CallableDescriptor): Boolean {
|
||||
if (descriptor.name.asString() != "contains") return false
|
||||
|
||||
+1
-2
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.codegen.range
|
||||
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.range.comparison.ComparisonGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.comparison.getComparisonGeneratorForRangeContainsCall
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.CallBasedInExpressionGenerator
|
||||
import org.jetbrains.kotlin.codegen.range.inExpression.InContinuousRangeExpressionGenerator
|
||||
@@ -33,7 +32,7 @@ abstract class PrimitiveNumberRangeIntrinsicRangeValue(rangeCall: ResolvedCall<o
|
||||
resolvedCallForIn.resultingDescriptor.let {
|
||||
isPrimitiveRangeContains(it) ||
|
||||
isClosedFloatingPointRangeContains(it) ||
|
||||
isIntPrimitiveRangeExtensionForInt(it)
|
||||
isPrimitiveNumberRangeExtensionContainsPrimitiveNumber(it)
|
||||
}
|
||||
|
||||
override fun createIntrinsicInExpressionGenerator(
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun inInt(x: Long): Boolean {
|
||||
return x in 1..2
|
||||
}
|
||||
|
||||
fun notInInt(x: Long): Boolean {
|
||||
return x !in 1..2
|
||||
}
|
||||
|
||||
fun inLong(x: Int): Boolean {
|
||||
return x in 1L..2L
|
||||
}
|
||||
|
||||
fun notInLong(x: Int): Boolean {
|
||||
return x !in 1L..2L
|
||||
}
|
||||
|
||||
fun inFloat(x: Double): Boolean {
|
||||
return x in 1.0f..2.0f
|
||||
}
|
||||
|
||||
fun notInFloat(x: Double): Boolean {
|
||||
return x !in 1.0f..2.0f
|
||||
}
|
||||
|
||||
fun inDouble(x: Float): Boolean {
|
||||
return x in 1.0..2.0
|
||||
}
|
||||
|
||||
fun notInDouble(x: Float): Boolean {
|
||||
return x !in 1.0..2.0
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
return when {
|
||||
!inInt(1L) -> "Fail !inInt"
|
||||
inInt(0L) -> "Fail inInt"
|
||||
notInInt(1L) -> "Fail notInInt"
|
||||
!notInInt(0L) -> "Fail !notInInt"
|
||||
!inLong(1) -> "Fail !inLong"
|
||||
inLong(0) -> "Fail inLong"
|
||||
notInLong(1) -> "Fail notInLong"
|
||||
!notInLong(0) -> "Fail !notInLong"
|
||||
!inFloat(1.0) -> "Fain !inFloat"
|
||||
inFloat(0.0) -> "Fain inFloat"
|
||||
notInFloat(1.0) -> "Fail notInFloat"
|
||||
!notInFloat(0.0) -> "Fail !notInFloat"
|
||||
!inDouble(1.0F) -> "Fail !inDouble"
|
||||
inDouble(0.0F) -> "Fail inDouble"
|
||||
notInDouble(1.0F) -> "Fail notInDouble"
|
||||
!notInDouble(0.0F) -> "Fail !notInDouble"
|
||||
else -> "OK"
|
||||
}
|
||||
}
|
||||
+9
-7
@@ -16,10 +16,12 @@ fun inDouble(x: Float): Boolean {
|
||||
return x in 1.0..2.0
|
||||
}
|
||||
|
||||
// 2 INVOKESPECIAL
|
||||
// 2 NEW
|
||||
// 2 INVOKESTATIC kotlin/ranges/RangesKt.rangeTo
|
||||
// 1 longRangeContains
|
||||
// 1 intRangeContains
|
||||
// 1 doubleRangeContains
|
||||
// 1 floatRangeContains
|
||||
// 3 I2L
|
||||
// 3 F2D
|
||||
// 0 INVOKESPECIAL
|
||||
// 0 NEW
|
||||
// 0 rangeTo
|
||||
// 0 longRangeContains
|
||||
// 0 intRangeContains
|
||||
// 0 doubleRangeContains
|
||||
// 0 floatRangeContains
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// WITH_RUNTIME
|
||||
|
||||
fun byteInFloat(x: Byte, a: Float, b: Float) = x in a .. b
|
||||
fun byteInDouble(x: Byte, a: Double, b: Double) = x in a .. b
|
||||
fun shortInFloat(x: Short, a: Float, b: Float) = x in a .. b
|
||||
fun shortInDouble(x: Short, a: Double, b: Double) = x in a .. b
|
||||
fun intInFloat(x: Int, a: Float, b: Float) = x in a .. b
|
||||
fun intInDouble(x: Int, a: Double, b: Double) = x in a .. b
|
||||
fun longInFloat(x: Long, a: Float, b: Float) = x in a .. b
|
||||
fun longInDouble(x: Long, a: Double, b: Double) = x in a .. b
|
||||
fun floatInInt(x: Float, a: Int, b: Int) = x in a .. b
|
||||
fun floatInLong(x: Float, a: Long, b: Long) = x in a .. b
|
||||
fun doubleInInt(x: Double, a: Int, b: Int) = x in a .. b
|
||||
fun doubleInLong(x: Double, a: Long, b: Long) = x in a .. b
|
||||
|
||||
// 4 INVOKESPECIAL
|
||||
// 4 NEW
|
||||
// 8 rangeTo
|
||||
// 2 longRangeContains
|
||||
// 2 intRangeContains
|
||||
// 4 doubleRangeContains
|
||||
// 4 floatRangeContains
|
||||
+6
@@ -13237,6 +13237,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inNonMatchingRange.kt")
|
||||
public void testInNonMatchingRange() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inNonMatchingRange.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inOptimizableDoubleRange.kt")
|
||||
public void testInOptimizableDoubleRange() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inOptimizableDoubleRange.kt");
|
||||
|
||||
@@ -13237,6 +13237,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inNonMatchingRange.kt")
|
||||
public void testInNonMatchingRange() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inNonMatchingRange.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inOptimizableDoubleRange.kt")
|
||||
public void testInOptimizableDoubleRange() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inOptimizableDoubleRange.kt");
|
||||
|
||||
@@ -1889,9 +1889,15 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inNonMatchingRange.kt")
|
||||
public void testInNonMatchingRange() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/ranges/inNonMatchingRange.kt");
|
||||
@TestMetadata("inNonMatchingRangeIntrinsified.kt")
|
||||
public void testInNonMatchingRangeIntrinsified() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/ranges/inNonMatchingRangeIntrinsified.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inNonMatchingRangeNotIntrinsified.kt")
|
||||
public void testInNonMatchingRangeNotIntrinsified() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/ranges/inNonMatchingRangeNotIntrinsified.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
|
||||
@@ -13237,6 +13237,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inNonMatchingRange.kt")
|
||||
public void testInNonMatchingRange() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inNonMatchingRange.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inOptimizableDoubleRange.kt")
|
||||
public void testInOptimizableDoubleRange() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inOptimizableDoubleRange.kt");
|
||||
|
||||
@@ -14869,6 +14869,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inNonMatchingRange.kt")
|
||||
public void testInNonMatchingRange() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inNonMatchingRange.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inOptimizableDoubleRange.kt")
|
||||
public void testInOptimizableDoubleRange() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/contains/inOptimizableDoubleRange.kt");
|
||||
|
||||
Reference in New Issue
Block a user