Support mod and floorDiv extensions in constant evaluator

Ignore evaluation tests for floorDiv and mod with FIR for now.
This commit is contained in:
Ilya Gorbunov
2021-02-21 06:05:03 +03:00
parent 58e6f775bb
commit 9cc8f44390
14 changed files with 206 additions and 18 deletions
@@ -8981,6 +8981,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/evaluate/binaryMinusIndependentExpType.kt");
}
@Test
@TestMetadata("customExtensionOverKotlinExtensionInConst.kt")
public void testCustomExtensionOverKotlinExtensionInConst() throws Exception {
runTest("compiler/testData/diagnostics/tests/evaluate/customExtensionOverKotlinExtensionInConst.kt");
}
@Test
@TestMetadata("divisionByZero.kt")
public void testDivisionByZero() throws Exception {
@@ -14290,6 +14290,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/evaluate/divide.kt");
}
@Test
@TestMetadata("floorDiv.kt")
public void testFloorDiv() throws Exception {
runTest("compiler/testData/codegen/box/evaluate/floorDiv.kt");
}
@Test
@TestMetadata("intrinsics.kt")
public void testIntrinsics() throws Exception {
@@ -14326,6 +14332,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/evaluate/minus.kt");
}
@Test
@TestMetadata("mod.kt")
public void testMod() throws Exception {
runTest("compiler/testData/codegen/box/evaluate/mod.kt");
}
@Test
@TestMetadata("multiply.kt")
public void testMultiply() throws Exception {
@@ -1,19 +1,7 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@file:Suppress("DEPRECATION", "DEPRECATION_ERROR", "NON_EXHAUSTIVE_WHEN")
package org.jetbrains.kotlin.resolve.constants.evaluate
@@ -143,6 +131,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Byte).plus(right as Byte)
"rem" -> return (left as Byte).rem(right as Byte)
"times" -> return (left as Byte).times(right as Byte)
"mod" -> return (left as Byte).mod(right as Byte)
"floorDiv" -> return (left as Byte).floorDiv(right as Byte)
}
DOUBLE -> when (name) {
"compareTo" -> return (left as Byte).compareTo(right as Double)
@@ -167,6 +157,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Byte).plus(right as Int)
"rem" -> return (left as Byte).rem(right as Int)
"times" -> return (left as Byte).times(right as Int)
"mod" -> return (left as Byte).mod(right as Int)
"floorDiv" -> return (left as Byte).floorDiv(right as Int)
}
LONG -> when (name) {
"compareTo" -> return (left as Byte).compareTo(right as Long)
@@ -175,6 +167,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Byte).plus(right as Long)
"rem" -> return (left as Byte).rem(right as Long)
"times" -> return (left as Byte).times(right as Long)
"mod" -> return (left as Byte).mod(right as Long)
"floorDiv" -> return (left as Byte).floorDiv(right as Long)
}
SHORT -> when (name) {
"compareTo" -> return (left as Byte).compareTo(right as Short)
@@ -183,6 +177,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Byte).plus(right as Short)
"rem" -> return (left as Byte).rem(right as Short)
"times" -> return (left as Byte).times(right as Short)
"mod" -> return (left as Byte).mod(right as Short)
"floorDiv" -> return (left as Byte).floorDiv(right as Short)
}
ANY -> when (name) {
"equals" -> return (left as Byte).equals(right)
@@ -217,6 +213,7 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Double).plus(right as Double)
"rem" -> return (left as Double).rem(right as Double)
"times" -> return (left as Double).times(right as Double)
"mod" -> return (left as Double).mod(right as Double)
}
FLOAT -> when (name) {
"compareTo" -> return (left as Double).compareTo(right as Float)
@@ -225,6 +222,7 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Double).plus(right as Float)
"rem" -> return (left as Double).rem(right as Float)
"times" -> return (left as Double).times(right as Float)
"mod" -> return (left as Double).mod(right as Float)
}
INT -> when (name) {
"compareTo" -> return (left as Double).compareTo(right as Int)
@@ -270,6 +268,7 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Float).plus(right as Double)
"rem" -> return (left as Float).rem(right as Double)
"times" -> return (left as Float).times(right as Double)
"mod" -> return (left as Float).mod(right as Double)
}
FLOAT -> when (name) {
"compareTo" -> return (left as Float).compareTo(right as Float)
@@ -278,6 +277,7 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Float).plus(right as Float)
"rem" -> return (left as Float).rem(right as Float)
"times" -> return (left as Float).times(right as Float)
"mod" -> return (left as Float).mod(right as Float)
}
INT -> when (name) {
"compareTo" -> return (left as Float).compareTo(right as Int)
@@ -321,6 +321,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"times" -> return (left as Int).times(right as Int)
"ushr" -> return (left as Int).ushr(right as Int)
"xor" -> return (left as Int).xor(right as Int)
"mod" -> return (left as Int).mod(right as Int)
"floorDiv" -> return (left as Int).floorDiv(right as Int)
}
BYTE -> when (name) {
"compareTo" -> return (left as Int).compareTo(right as Byte)
@@ -329,6 +331,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Int).plus(right as Byte)
"rem" -> return (left as Int).rem(right as Byte)
"times" -> return (left as Int).times(right as Byte)
"mod" -> return (left as Int).mod(right as Byte)
"floorDiv" -> return (left as Int).floorDiv(right as Byte)
}
DOUBLE -> when (name) {
"compareTo" -> return (left as Int).compareTo(right as Double)
@@ -353,6 +357,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Int).plus(right as Long)
"rem" -> return (left as Int).rem(right as Long)
"times" -> return (left as Int).times(right as Long)
"mod" -> return (left as Int).mod(right as Long)
"floorDiv" -> return (left as Int).floorDiv(right as Long)
}
SHORT -> when (name) {
"compareTo" -> return (left as Int).compareTo(right as Short)
@@ -361,6 +367,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Int).plus(right as Short)
"rem" -> return (left as Int).rem(right as Short)
"times" -> return (left as Int).times(right as Short)
"mod" -> return (left as Int).mod(right as Short)
"floorDiv" -> return (left as Int).floorDiv(right as Short)
}
ANY -> when (name) {
"equals" -> return (left as Int).equals(right)
@@ -377,6 +385,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"rem" -> return (left as Long).rem(right as Long)
"times" -> return (left as Long).times(right as Long)
"xor" -> return (left as Long).xor(right as Long)
"mod" -> return (left as Long).mod(right as Long)
"floorDiv" -> return (left as Long).floorDiv(right as Long)
}
BYTE -> when (name) {
"compareTo" -> return (left as Long).compareTo(right as Byte)
@@ -385,6 +395,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Long).plus(right as Byte)
"rem" -> return (left as Long).rem(right as Byte)
"times" -> return (left as Long).times(right as Byte)
"mod" -> return (left as Long).mod(right as Byte)
"floorDiv" -> return (left as Long).floorDiv(right as Byte)
}
DOUBLE -> when (name) {
"compareTo" -> return (left as Long).compareTo(right as Double)
@@ -412,6 +424,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"shr" -> return (left as Long).shr(right as Int)
"times" -> return (left as Long).times(right as Int)
"ushr" -> return (left as Long).ushr(right as Int)
"mod" -> return (left as Long).mod(right as Int)
"floorDiv" -> return (left as Long).floorDiv(right as Int)
}
SHORT -> when (name) {
"compareTo" -> return (left as Long).compareTo(right as Short)
@@ -420,6 +434,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Long).plus(right as Short)
"rem" -> return (left as Long).rem(right as Short)
"times" -> return (left as Long).times(right as Short)
"mod" -> return (left as Long).mod(right as Short)
"floorDiv" -> return (left as Long).floorDiv(right as Short)
}
ANY -> when (name) {
"equals" -> return (left as Long).equals(right)
@@ -433,6 +449,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Short).plus(right as Byte)
"rem" -> return (left as Short).rem(right as Byte)
"times" -> return (left as Short).times(right as Byte)
"mod" -> return (left as Short).mod(right as Byte)
"floorDiv" -> return (left as Short).floorDiv(right as Byte)
}
DOUBLE -> when (name) {
"compareTo" -> return (left as Short).compareTo(right as Double)
@@ -457,6 +475,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Short).plus(right as Int)
"rem" -> return (left as Short).rem(right as Int)
"times" -> return (left as Short).times(right as Int)
"mod" -> return (left as Short).mod(right as Int)
"floorDiv" -> return (left as Short).floorDiv(right as Int)
}
LONG -> when (name) {
"compareTo" -> return (left as Short).compareTo(right as Long)
@@ -465,6 +485,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Short).plus(right as Long)
"rem" -> return (left as Short).rem(right as Long)
"times" -> return (left as Short).times(right as Long)
"mod" -> return (left as Short).mod(right as Long)
"floorDiv" -> return (left as Short).floorDiv(right as Long)
}
SHORT -> when (name) {
"compareTo" -> return (left as Short).compareTo(right as Short)
@@ -473,6 +495,8 @@ internal fun evalBinaryOp(name: String, leftType: CompileTimeType, left: Any, ri
"plus" -> return (left as Short).plus(right as Short)
"rem" -> return (left as Short).rem(right as Short)
"times" -> return (left as Short).times(right as Short)
"mod" -> return (left as Short).mod(right as Short)
"floorDiv" -> return (left as Short).floorDiv(right as Short)
}
ANY -> when (name) {
"equals" -> return (left as Short).equals(right)
+24
View File
@@ -0,0 +1,24 @@
// IGNORE_FIR_DIAGNOSTICS
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
@Retention(AnnotationRetention.RUNTIME)
annotation class Ann(
val b: Byte,
val s: Short,
val i: Int,
val l: Long
)
@Ann(10.floorDiv(3), 10.floorDiv(-4), (-10).floorDiv(5), (-10).floorDiv(-6)) class MyClass
fun box(): String {
val annotation = MyClass::class.java.getAnnotation(Ann::class.java)!!
if (annotation.b != 3.toByte()) return "fail 1"
if (annotation.s != (-3).toShort()) return "fail 2"
if (annotation.i != -2) return "fail 3"
if (annotation.l != 1L) return "fail 4"
return "OK"
}
+35
View File
@@ -0,0 +1,35 @@
// IGNORE_FIR_DIAGNOSTICS
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
@Retention(AnnotationRetention.RUNTIME)
annotation class Ann(
val p1: Byte,
val p2: Short,
val p3: Int,
val p4: Long,
val p5: Double,
val p6: Float
)
val prop1: Byte = 10.mod(2)
val prop2: Short = 10.mod(-3)
val prop3: Int = (-10).mod(4)
val prop4: Long = (-10).mod(-5)
val prop5: Double = 0.25.mod(-100.0)
val prop6: Float = 100f.mod(0.33f)
@Ann(10.mod(2), 10.mod(-3), (-10).mod(4), (-10).mod(5), 0.25.mod(-100.0), 100f.mod(0.33f)) class MyClass
fun box(): String {
val annotation = MyClass::class.java.getAnnotation(Ann::class.java)!!
if (annotation.p1 != prop1) return "fail 1, expected = ${prop1}, actual = ${annotation.p1}"
if (annotation.p2 != prop2) return "fail 2, expected = ${prop2}, actual = ${annotation.p2}"
if (annotation.p3 != prop3) return "fail 3, expected = ${prop3}, actual = ${annotation.p3}"
if (annotation.p4 != prop4) return "fail 4, expected = ${prop4}, actual = ${annotation.p4}"
if (annotation.p5 != prop5) return "fail 5, expected = ${prop5}, actual = ${annotation.p5}"
if (annotation.p6 != prop6) return "fail 6, expected = ${prop6}, actual = ${annotation.p6}"
return "OK"
}
@@ -0,0 +1,7 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE, -UNUSED_PARAMETER
fun Int.mod(other: Int) = 10
fun Int.floorDiv(other: Int): Int = 20
const val a1 = (-5).mod(2)
const val b1 = 5.floorDiv(3)
@@ -0,0 +1,7 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE, -UNUSED_PARAMETER
fun Int.mod(other: Int) = 10
fun Int.floorDiv(other: Int): Int = 20
const val a1 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>(-5).mod(2)<!>
const val b1 = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>5.floorDiv(3)<!>
@@ -0,0 +1,6 @@
package
public const val a1: kotlin.Int
public const val b1: kotlin.Int
public fun kotlin.Int.floorDiv(/*0*/ other: kotlin.Int): kotlin.Int
public fun kotlin.Int.mod(/*0*/ other: kotlin.Int): kotlin.Int
+7 -1
View File
@@ -20,4 +20,10 @@ val x5 = 0x1234 and 0x5678
val x6 = 0x1234 and 0x5678L
// val x7: 4656.toLong()
val x7 = 0x1234L and 0x5678
val x7 = 0x1234L and 0x5678
// val x8: -123457
val x8 = (-123_456_789_321).floorDiv(1_000_000)
// val x9: 79
val x9 = (-123_456_789_321).mod(100)
@@ -8987,6 +8987,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/evaluate/binaryMinusIndependentExpType.kt");
}
@Test
@TestMetadata("customExtensionOverKotlinExtensionInConst.kt")
public void testCustomExtensionOverKotlinExtensionInConst() throws Exception {
runTest("compiler/testData/diagnostics/tests/evaluate/customExtensionOverKotlinExtensionInConst.kt");
}
@Test
@TestMetadata("divisionByZero.kt")
public void testDivisionByZero() throws Exception {
@@ -14290,6 +14290,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/evaluate/divide.kt");
}
@Test
@TestMetadata("floorDiv.kt")
public void testFloorDiv() throws Exception {
runTest("compiler/testData/codegen/box/evaluate/floorDiv.kt");
}
@Test
@TestMetadata("intrinsics.kt")
public void testIntrinsics() throws Exception {
@@ -14326,6 +14332,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/evaluate/minus.kt");
}
@Test
@TestMetadata("mod.kt")
public void testMod() throws Exception {
runTest("compiler/testData/codegen/box/evaluate/mod.kt");
}
@Test
@TestMetadata("multiply.kt")
public void testMultiply() throws Exception {
@@ -14290,6 +14290,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/evaluate/divide.kt");
}
@Test
@TestMetadata("floorDiv.kt")
public void testFloorDiv() throws Exception {
runTest("compiler/testData/codegen/box/evaluate/floorDiv.kt");
}
@Test
@TestMetadata("intrinsics.kt")
public void testIntrinsics() throws Exception {
@@ -14326,6 +14332,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/evaluate/minus.kt");
}
@Test
@TestMetadata("mod.kt")
public void testMod() throws Exception {
runTest("compiler/testData/codegen/box/evaluate/mod.kt");
}
@Test
@TestMetadata("multiply.kt")
public void testMultiply() throws Exception {
@@ -11749,6 +11749,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/evaluate/divide.kt");
}
@TestMetadata("floorDiv.kt")
public void testFloorDiv() throws Exception {
runTest("compiler/testData/codegen/box/evaluate/floorDiv.kt");
}
@TestMetadata("intrinsics.kt")
public void testIntrinsics() throws Exception {
runTest("compiler/testData/codegen/box/evaluate/intrinsics.kt");
@@ -11779,6 +11784,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/evaluate/minus.kt");
}
@TestMetadata("mod.kt")
public void testMod() throws Exception {
runTest("compiler/testData/codegen/box/evaluate/mod.kt");
}
@TestMetadata("multiply.kt")
public void testMultiply() throws Exception {
runTest("compiler/testData/codegen/box/evaluate/multiply.kt");
+24 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -26,7 +26,7 @@ fun main() {
fun generate(): String {
val sb = StringBuilder()
val p = Printer(sb)
p.println(File("license/COPYRIGHT.txt").readText())
p.println(File("license/COPYRIGHT_HEADER.txt").readText())
p.println("@file:Suppress(\"DEPRECATION\", \"DEPRECATION_ERROR\", \"NON_EXHAUSTIVE_WHEN\")")
p.println()
@@ -47,6 +47,9 @@ fun generate(): String {
val allPrimitiveTypes = builtIns.builtInsPackageScope.getContributedDescriptors()
.filter { it is ClassDescriptor && KotlinBuiltIns.isPrimitiveType(it.defaultType) } as List<ClassDescriptor>
val integerTypes = allPrimitiveTypes.map { it.defaultType }.filter { it.isIntegerType() }
val fpTypes = allPrimitiveTypes.map { it.defaultType }.filter { it.isFpType() }
for (descriptor in allPrimitiveTypes + builtIns.string) {
@Suppress("UNCHECKED_CAST")
val functions = descriptor.getMemberScope(listOf()).getContributedDescriptors()
@@ -65,6 +68,21 @@ fun generate(): String {
}
}
for (type in integerTypes) {
for (otherType in integerTypes) {
val parameters = listOf(type, otherType)
binaryOperationsMap.add("mod" to parameters)
binaryOperationsMap.add("floorDiv" to parameters)
}
}
for (type in fpTypes) {
for (otherType in fpTypes) {
val parameters = listOf(type, otherType)
binaryOperationsMap.add("mod" to parameters)
}
}
p.println("internal fun evalUnaryOp(name: String, type: CompileTimeType, value: Any): Any? {")
p.pushIndent()
p.println("when (type) {")
@@ -155,7 +173,7 @@ private fun getBinaryCheckerName(name: String, leftType: KotlinType, rightType:
"minus" -> "subtract"
"div" -> "divide"
"times" -> "multiply"
"mod", "rem", "xor", "or", "and" -> name
"rem", "xor", "or", "and" -> name
else -> null
}
}
@@ -163,6 +181,9 @@ private fun getBinaryCheckerName(name: String, leftType: KotlinType, rightType:
private fun KotlinType.isIntegerType(): Boolean =
KotlinBuiltIns.isInt(this) || KotlinBuiltIns.isShort(this) || KotlinBuiltIns.isByte(this) || KotlinBuiltIns.isLong(this)
private fun KotlinType.isFpType(): Boolean =
KotlinBuiltIns.isDouble(this) || KotlinBuiltIns.isFloat(this)
private fun CallableDescriptor.getParametersTypes(): List<KotlinType> =
listOf((containingDeclaration as ClassDescriptor).defaultType) +
valueParameters.map { it.type.makeNotNullable() }