[FIR] Support constant unary operators for integer literal operators
^KT-38895
This commit is contained in:
committed by
teamcity
parent
52b72a7dac
commit
1591518cf6
+6
@@ -17486,6 +17486,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/integerLiterals"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constantUnaryOperators.kt")
|
||||
public void testConstantUnaryOperators() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/integerLiterals/constantUnaryOperators.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intToLongConversion.kt")
|
||||
public void testIntToLongConversion() throws Exception {
|
||||
|
||||
+6
@@ -17486,6 +17486,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/integerLiterals"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constantUnaryOperators.kt")
|
||||
public void testConstantUnaryOperators() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/integerLiterals/constantUnaryOperators.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intToLongConversion.kt")
|
||||
public void testIntToLongConversion() throws Exception {
|
||||
|
||||
+6
@@ -17486,6 +17486,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/integerLiterals"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constantUnaryOperators.kt")
|
||||
public void testConstantUnaryOperators() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/integerLiterals/constantUnaryOperators.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intToLongConversion.kt")
|
||||
public void testIntToLongConversion() throws Exception {
|
||||
|
||||
+9
-5
@@ -5,15 +5,19 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
|
||||
object ConvertibleIntegerOperators {
|
||||
val operatorsNames: Set<Name> = listOf(
|
||||
val binaryOperatorsNames: Set<Name> = listOf(
|
||||
"plus", "minus", "times", "div", "rem",
|
||||
"and", "or", "xor",
|
||||
"shl", "shr", "ushr"
|
||||
).mapTo(mutableSetOf()) { Name.identifier(it) }
|
||||
).toNameSet()
|
||||
|
||||
// Constant conversion for those unary operators works only for signed integers
|
||||
val unaryOperatorNames: Set<Name> = listOf(
|
||||
"inv", "unaryPlus", "unaryMinus"
|
||||
).toNameSet()
|
||||
|
||||
private fun List<String>.toNameSet(): Set<Name> = mapTo(mutableSetOf()) { Name.identifier(it) }
|
||||
}
|
||||
|
||||
+7
-1
@@ -40,12 +40,18 @@ class FirIntegerConstantOperatorScope(
|
||||
private val mappedFunctions = mutableMapOf<Name, FirNamedFunctionSymbol>()
|
||||
|
||||
override fun processFunctionsByName(name: Name, processor: (FirNamedFunctionSymbol) -> Unit) {
|
||||
if (name !in ConvertibleIntegerOperators.operatorsNames) {
|
||||
// Constant conversion for those unary operators works only for signed integers
|
||||
val isUnaryOperator = !isUnsigned && (name in ConvertibleIntegerOperators.unaryOperatorNames)
|
||||
val isBinaryOperator = name in ConvertibleIntegerOperators.binaryOperatorsNames
|
||||
if (!isUnaryOperator && !isBinaryOperator) {
|
||||
return baseScope.processFunctionsByName(name, processor)
|
||||
}
|
||||
val wrappedSymbol = mappedFunctions.getOrPut(name) {
|
||||
val allFunctions = baseScope.getFunctions(name)
|
||||
val functionSymbol = allFunctions.first {
|
||||
// unary operators have only one overload
|
||||
if (isUnaryOperator) return@first true
|
||||
|
||||
val coneType = it.fir.valueParameters.first().returnTypeRef.coneType
|
||||
if (isUnsigned) {
|
||||
coneType.isUInt
|
||||
|
||||
@@ -94,6 +94,8 @@ class CandidateFactory private constructor(
|
||||
|
||||
private fun FirBasedSymbol<*>.unwrapIntegerOperatorSymbolIfNeeded(callInfo: CallInfo): FirBasedSymbol<*> {
|
||||
if (this !is FirNamedFunctionSymbol) return this
|
||||
// There is no need to unwrap unary operators
|
||||
if (fir.valueParameters.isEmpty()) return this
|
||||
val original = fir.originalForWrappedIntegerOperator ?: return this
|
||||
return if (callInfo.arguments.first().isIntegerLiteralOrOperatorCall()) {
|
||||
this
|
||||
|
||||
+7
-2
@@ -395,8 +395,13 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
||||
} ?: return this
|
||||
if (!resolvedSymbol.isWrappedIntegerOperator()) return this
|
||||
|
||||
val argument = this.argumentList.arguments.singleOrNull() ?: return this
|
||||
assert(argument.isIntegerLiteralOrOperatorCall())
|
||||
val arguments = this.argumentList.arguments
|
||||
val argument = when (arguments.size) {
|
||||
0 -> null
|
||||
1 -> arguments.first()
|
||||
else -> return this
|
||||
}
|
||||
assert(argument?.isIntegerLiteralOrOperatorCall() != false)
|
||||
|
||||
val originalCall = this
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// FIR status: don't support legacy feature; for reasons this test is ignored, go to KT-46419
|
||||
|
||||
fun box(): String {
|
||||
val a: Long = -(1 shl 31)
|
||||
if (a != -2147483648L) return "fail: in this case we should add to ints and than cast the result to long - overflow expected"
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
FILE: constantUnaryOperators.kt
|
||||
public final val i1: R|kotlin/Int| = Int(2).R|kotlin/Int.plus|(Int(2).R|kotlin/Int.times|(Int(3))).R|kotlin/Int.inv|()
|
||||
public get(): R|kotlin/Int|
|
||||
public final val l1: R|kotlin/Long| = Int(2).R|kotlin/Int.plus|(Int(2).R|kotlin/Int.times|(Int(3))).R|kotlin/Int.inv|().R|kotlin/Int.toLong|()
|
||||
public get(): R|kotlin/Long|
|
||||
public final val ll1: R|kotlin/Long| = Long(3000000000).R|kotlin/Long.times|(Int(2)).R|kotlin/Long.plus|(Int(1)).R|kotlin/Long.inv|()
|
||||
public get(): R|kotlin/Long|
|
||||
public final val i2: R|kotlin/Int| = Int(2).R|kotlin/Int.plus|(Int(2).R|kotlin/Int.times|(Int(3))).R|kotlin/Int.unaryPlus|()
|
||||
public get(): R|kotlin/Int|
|
||||
public final val l2: R|kotlin/Long| = Int(2).R|kotlin/Int.plus|(Int(2).R|kotlin/Int.times|(Int(3))).R|kotlin/Int.unaryPlus|().R|kotlin/Int.toLong|()
|
||||
public get(): R|kotlin/Long|
|
||||
public final val ll2: R|kotlin/Long| = Long(3000000000).R|kotlin/Long.times|(Int(2)).R|kotlin/Long.plus|(Int(1)).R|kotlin/Long.unaryPlus|()
|
||||
public get(): R|kotlin/Long|
|
||||
public final val i3: R|kotlin/Int| = Int(2).R|kotlin/Int.plus|(Int(2).R|kotlin/Int.times|(Int(3))).R|kotlin/Int.unaryMinus|()
|
||||
public get(): R|kotlin/Int|
|
||||
public final val l3: R|kotlin/Long| = Int(2).R|kotlin/Int.plus|(Int(2).R|kotlin/Int.times|(Int(3))).R|kotlin/Int.unaryMinus|().R|kotlin/Int.toLong|()
|
||||
public get(): R|kotlin/Long|
|
||||
public final val ll3: R|kotlin/Long| = Long(3000000000).R|kotlin/Long.times|(Int(2)).R|kotlin/Long.plus|(Int(1)).R|kotlin/Long.unaryMinus|()
|
||||
public get(): R|kotlin/Long|
|
||||
public final val i4: R|kotlin/Int| = Int(2).R|kotlin/Int.plus|(Int(2).R|kotlin/Int.times|(Int(3))).R|kotlin/Int.inc|()
|
||||
public get(): R|kotlin/Int|
|
||||
public final val l4: R|kotlin/Long| = Int(2).R|kotlin/Int.plus|(Int(2).R|kotlin/Int.times|(Int(3))).<CS errors: kotlin/Int.inc>#()
|
||||
public get(): R|kotlin/Long|
|
||||
public final val ll4: R|kotlin/Long| = Long(3000000000).R|kotlin/Long.times|(Int(2)).R|kotlin/Long.plus|(Int(1)).R|kotlin/Long.inc|()
|
||||
public get(): R|kotlin/Long|
|
||||
public final val i5: R|kotlin/Int| = Int(2).R|kotlin/Int.plus|(Int(2).R|kotlin/Int.times|(Int(3))).R|kotlin/Int.dec|()
|
||||
public get(): R|kotlin/Int|
|
||||
public final val l5: R|kotlin/Long| = Int(2).R|kotlin/Int.plus|(Int(2).R|kotlin/Int.times|(Int(3))).<CS errors: kotlin/Int.dec>#()
|
||||
public get(): R|kotlin/Long|
|
||||
public final val ll5: R|kotlin/Long| = Long(3000000000).R|kotlin/Long.times|(Int(2)).R|kotlin/Long.plus|(Int(1)).R|kotlin/Long.dec|()
|
||||
public get(): R|kotlin/Long|
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// FIR_IDENTICAL
|
||||
// SKIP_TXT
|
||||
// FIR_DUMP
|
||||
|
||||
// ------------- const -------------
|
||||
|
||||
val i1 = (2 + 2 * 3).inv()
|
||||
val l1: Long = (2 + 2 * 3).inv()
|
||||
val ll1 = (3000000000 * 2 + 1).inv()
|
||||
|
||||
val i2 = (2 + 2 * 3).unaryPlus()
|
||||
val l2: Long = (2 + 2 * 3).unaryPlus()
|
||||
val ll2 = (3000000000 * 2 + 1).unaryPlus()
|
||||
|
||||
val i3 = (2 + 2 * 3).unaryMinus()
|
||||
val l3: Long = (2 + 2 * 3).unaryMinus()
|
||||
val ll3 = (3000000000 * 2 + 1).unaryMinus()
|
||||
|
||||
// ------------- non const -------------
|
||||
|
||||
val i4 = (2 + 2 * 3).inc()
|
||||
val l4: Long = <!TYPE_MISMATCH!>(2 + 2 * 3).inc()<!>
|
||||
val ll4 = (3000000000 * 2 + 1).inc()
|
||||
|
||||
val i5 = (2 + 2 * 3).dec()
|
||||
val l5: Long = <!TYPE_MISMATCH!>(2 + 2 * 3).dec()<!>
|
||||
val ll5 = (3000000000 * 2 + 1).dec()
|
||||
+3
-3
@@ -14,15 +14,15 @@ fun testLongDotCall(c1: C<Long>) {
|
||||
c1.takeT(1.rem(2))
|
||||
c1.takeT(<!ARGUMENT_TYPE_MISMATCH!>1.inc()<!>)
|
||||
c1.takeT(<!ARGUMENT_TYPE_MISMATCH!>1.dec()<!>)
|
||||
c1.takeT(<!ARGUMENT_TYPE_MISMATCH!>1.unaryPlus()<!>)
|
||||
c1.takeT(<!ARGUMENT_TYPE_MISMATCH!>1.unaryMinus()<!>)
|
||||
c1.takeT(1.unaryPlus())
|
||||
c1.takeT(1.unaryMinus())
|
||||
c1.takeT(1.shl(2))
|
||||
c1.takeT(1.shr(2))
|
||||
c1.takeT(1.ushr(2))
|
||||
c1.takeT(1.and(2))
|
||||
c1.takeT(1.or(2))
|
||||
c1.takeT(1.xor(2))
|
||||
c1.takeT(<!ARGUMENT_TYPE_MISMATCH!>1.inv()<!>)
|
||||
c1.takeT(1.inv())
|
||||
}
|
||||
|
||||
fun testShortDotCall(c2: C<Short>) {
|
||||
|
||||
Vendored
+3
-3
@@ -70,9 +70,9 @@ fun testLongUnaryOperators() {
|
||||
takeLong(-1)
|
||||
|
||||
// Mismatch
|
||||
takeLong(<!ARGUMENT_TYPE_MISMATCH!>2.unaryPlus()<!>)
|
||||
takeLong(<!ARGUMENT_TYPE_MISMATCH!>2.unaryMinus()<!>)
|
||||
takeLong(<!ARGUMENT_TYPE_MISMATCH!>2.inv()<!>)
|
||||
takeLong(2.unaryPlus())
|
||||
takeLong(2.unaryMinus())
|
||||
takeLong(2.inv())
|
||||
takeLong(<!ARGUMENT_TYPE_MISMATCH!>1.inc()<!>)
|
||||
takeLong(<!ARGUMENT_TYPE_MISMATCH!>1.dec()<!>)
|
||||
}
|
||||
|
||||
+3
-3
@@ -68,9 +68,9 @@ fun testLongUnaryOperators() {
|
||||
// Won't change
|
||||
takeLong(+1)
|
||||
takeLong(-1)
|
||||
takeLong(<!ARGUMENT_TYPE_MISMATCH!>2.unaryPlus()<!>)
|
||||
takeLong(<!ARGUMENT_TYPE_MISMATCH!>2.unaryMinus()<!>)
|
||||
takeLong(<!ARGUMENT_TYPE_MISMATCH!>2.inv()<!>)
|
||||
takeLong(2.unaryPlus())
|
||||
takeLong(2.unaryMinus())
|
||||
takeLong(2.inv())
|
||||
|
||||
// Will change
|
||||
takeLong(<!ARGUMENT_TYPE_MISMATCH!>1.inc()<!>)
|
||||
|
||||
Generated
+6
@@ -17492,6 +17492,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/integerLiterals"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("constantUnaryOperators.kt")
|
||||
public void testConstantUnaryOperators() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/integerLiterals/constantUnaryOperators.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("intToLongConversion.kt")
|
||||
public void testIntToLongConversion() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user