Skip to content

Commit a257a25

Browse files
flofridaySpace Team
authored andcommitted
[FIR] Add evaluation of unsigned constants to the frontend
There already was some implementation for unsigned literals but now the frontend evaluator also supports operations on unsigned literals. KT-51065
1 parent 7c0d7ef commit a257a25

File tree

12 files changed

+534
-521
lines changed

12 files changed

+534
-521
lines changed

compiler/fir/providers/src/org/jetbrains/kotlin/fir/expressions/FirConstChecks.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ private class FirConstCheckVisitor(
205205
return ConstantArgumentKind.NOT_CONST
206206
}
207207

208-
if (!exp.hasAllowedCompileTimeType() || exp.getExpandedType().isUnsignedType) {
208+
if (!exp.hasAllowedCompileTimeType() || (!intrinsicConstEvaluation && exp.getExpandedType().isUnsignedType)) {
209209
return ConstantArgumentKind.NOT_CONST
210210
}
211211

@@ -458,13 +458,14 @@ private class FirConstCheckVisitor(
458458

459459
val receiverClassId = this.dispatchReceiver?.getExpandedType()?.classId
460460

461-
if (receiverClassId in StandardClassIds.unsignedTypes) return false
461+
if (!intrinsicConstEvaluation && receiverClassId in StandardClassIds.unsignedTypes) return false
462462

463463
if (
464464
name in compileTimeFunctions ||
465465
name in compileTimeExtensionFunctions ||
466466
name == OperatorNameConventions.TO_STRING ||
467-
name in OperatorNameConventions.NUMBER_CONVERSIONS
467+
name in OperatorNameConventions.NUMBER_CONVERSIONS ||
468+
(intrinsicConstEvaluation && name in OperatorNameConventions.UNSIGNED_CONVERSIONS)
468469
) return true
469470

470471
if (calleeReference.name == OperatorNameConventions.GET && receiverClassId == StandardClassIds.String) return true

compiler/fir/providers/src/org/jetbrains/kotlin/fir/expressions/FirExpressionEvaluator.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,10 @@ private fun ConstantValueKind.toCompileTimeType(): CompileTimeType {
427427
ConstantValueKind.Short -> CompileTimeType.SHORT
428428
ConstantValueKind.Int -> CompileTimeType.INT
429429
ConstantValueKind.Long -> CompileTimeType.LONG
430+
ConstantValueKind.UnsignedByte -> CompileTimeType.UBYTE
431+
ConstantValueKind.UnsignedShort -> CompileTimeType.USHORT
432+
ConstantValueKind.UnsignedInt -> CompileTimeType.UINT
433+
ConstantValueKind.UnsignedLong -> CompileTimeType.ULONG
430434
ConstantValueKind.Double -> CompileTimeType.DOUBLE
431435
ConstantValueKind.Float -> CompileTimeType.FLOAT
432436
ConstantValueKind.Char -> CompileTimeType.CHAR

compiler/testData/codegen/box/involvesIrInterpreter/ubyteOperations.kt

Lines changed: 109 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,111 @@
1-
// IGNORE_BACKEND_K1: JS_IR, JS_IR_ES6, WASM_JS, WASM_WASI
2-
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6, WASM_JS, WASM_WASI
3-
// IGNORE_IR_DESERIALIZATION_TEST: NATIVE
4-
// ^^^ Ignore Backends that apply inliner before interpreter, which messes with the interpreter.
5-
// TODO, KT-80561: Reenable all backends, once unsigned operations are supported in the frontend.
1+
// LANGUAGE: +IntrinsicConstEvaluation
2+
// IGNORE_BACKEND_K1: ANY
3+
// ^^^^^^^^^^^^^^^^^^^^^^ Unsigned operations will not be supported in the legacy K1 frontend.
64
// WITH_STDLIB
75
fun <T> T.id() = this
86

9-
val compareTo1 = 1u.toUByte().<!EVALUATED{IR}("-1")!>compareTo(2u.toUByte())<!>
10-
val compareTo2 = 2u.toUByte().<!EVALUATED{IR}("0")!>compareTo(2u.toUByte())<!>
11-
val compareTo3 = 3u.toUByte().<!EVALUATED{IR}("1")!>compareTo(2u.toUByte())<!>
12-
val compareTo4 = 2u.toUByte().<!EVALUATED{IR}("0")!>compareTo(2u.toUShort())<!>
13-
val compareTo5 = 2u.toUByte().<!EVALUATED{IR}("0")!>compareTo(2u)<!>
14-
val compareTo6 = 2u.toUByte().<!EVALUATED{IR}("0")!>compareTo(2UL)<!>
15-
16-
val plus1 = 1u.toUByte().<!EVALUATED{IR}("3")!>plus(2u.toUByte())<!>
17-
val plus2 = 2u.toUByte().<!EVALUATED{IR}("4")!>plus(2u.toUByte())<!>
18-
val plus3 = 3u.toUByte().<!EVALUATED{IR}("5")!>plus(2u.toUByte())<!>
19-
val plus4 = 2u.toUByte().<!EVALUATED{IR}("4")!>plus(2u.toUShort())<!>
20-
val plus5 = 2u.toUByte().<!EVALUATED{IR}("4")!>plus(2u)<!>
21-
val plus6 = 2u.toUByte().<!EVALUATED{IR}("4")!>plus(2UL)<!>
22-
23-
val minus1 = 1u.toUByte().<!EVALUATED{IR}("4294967295")!>minus(2u.toUByte())<!>
24-
val minus2 = 2u.toUByte().<!EVALUATED{IR}("0")!>minus(2u.toUByte())<!>
25-
val minus3 = 3u.toUByte().<!EVALUATED{IR}("1")!>minus(2u.toUByte())<!>
26-
val minus4 = 2u.toUByte().<!EVALUATED{IR}("0")!>minus(2u.toUShort())<!>
27-
val minus5 = 2u.toUByte().<!EVALUATED{IR}("0")!>minus(2u)<!>
28-
val minus6 = 2u.toUByte().<!EVALUATED{IR}("0")!>minus(2UL)<!>
29-
30-
val times1 = 1u.toUByte().<!EVALUATED{IR}("2")!>times(2u.toUByte())<!>
31-
val times2 = 2u.toUByte().<!EVALUATED{IR}("4")!>times(2u.toUByte())<!>
32-
val times3 = 3u.toUByte().<!EVALUATED{IR}("6")!>times(2u.toUByte())<!>
33-
val times4 = 2u.toUByte().<!EVALUATED{IR}("4")!>times(2u.toUShort())<!>
34-
val times5 = 2u.toUByte().<!EVALUATED{IR}("4")!>times(2u)<!>
35-
val times6 = 2u.toUByte().<!EVALUATED{IR}("4")!>times(2UL)<!>
36-
37-
val div1 = 1u.toUByte().<!EVALUATED{IR}("0")!>div(2u.toUByte())<!>
38-
val div2 = 2u.toUByte().<!EVALUATED{IR}("1")!>div(2u.toUByte())<!>
39-
val div3 = 3u.toUByte().<!EVALUATED{IR}("1")!>div(2u.toUByte())<!>
40-
val div4 = 2u.toUByte().<!EVALUATED{IR}("1")!>div(2u.toUShort())<!>
41-
val div5 = 2u.toUByte().<!EVALUATED{IR}("1")!>div(2u)<!>
42-
val div6 = 2u.toUByte().<!EVALUATED{IR}("1")!>div(2UL)<!>
43-
44-
val floorDiv1 = 1u.toUByte().<!EVALUATED{IR}("0")!>floorDiv(2u.toUByte())<!>
45-
val floorDiv2 = 2u.toUByte().<!EVALUATED{IR}("1")!>floorDiv(2u.toUByte())<!>
46-
val floorDiv3 = 3u.toUByte().<!EVALUATED{IR}("1")!>floorDiv(2u.toUByte())<!>
47-
val floorDiv4 = 2u.toUByte().<!EVALUATED{IR}("1")!>floorDiv(2u.toUShort())<!>
48-
val floorDiv5 = 2u.toUByte().<!EVALUATED{IR}("1")!>floorDiv(2u)<!>
49-
val floorDiv6 = 2u.toUByte().<!EVALUATED{IR}("1")!>floorDiv(2UL)<!>
50-
51-
val rem1 = 1u.toUByte().<!EVALUATED{IR}("1")!>rem(2u.toUByte())<!>
52-
val rem2 = 2u.toUByte().<!EVALUATED{IR}("0")!>rem(2u.toUByte())<!>
53-
val rem3 = 3u.toUByte().<!EVALUATED{IR}("1")!>rem(2u.toUByte())<!>
54-
val rem4 = 2u.toUByte().<!EVALUATED{IR}("0")!>rem(2u.toUShort())<!>
55-
val rem5 = 2u.toUByte().<!EVALUATED{IR}("0")!>rem(2u)<!>
56-
val rem6 = 2u.toUByte().<!EVALUATED{IR}("0")!>rem(2UL)<!>
57-
58-
val mod1 = 1u.toUByte().<!EVALUATED{IR}("1")!>mod(2u.toUByte())<!>
59-
val mod2 = 2u.toUByte().<!EVALUATED{IR}("0")!>mod(2u.toUByte())<!>
60-
val mod3 = 3u.toUByte().<!EVALUATED{IR}("1")!>mod(2u.toUByte())<!>
61-
val mod4 = 2u.toUByte().<!EVALUATED{IR}("0")!>mod(2u.toUShort())<!>
62-
val mod5 = 2u.toUByte().<!EVALUATED{IR}("0")!>mod(2u)<!>
63-
val mod6 = 2u.toUByte().<!EVALUATED{IR}("0")!>mod(2UL)<!>
64-
65-
val and1 = 1u.toUByte().<!EVALUATED{IR}("0")!>and(2u.toUByte())<!>
66-
val and2 = 2u.toUByte().<!EVALUATED{IR}("2")!>and(2u.toUByte())<!>
67-
val and3 = 3u.toUByte().<!EVALUATED{IR}("2")!>and(2u.toUByte())<!>
68-
val and4 = 12u.toUByte().<!EVALUATED{IR}("8")!>and(10u.toUByte())<!>
69-
70-
val or1 = 1u.toUByte().<!EVALUATED{IR}("3")!>or(2u.toUByte())<!>
71-
val or2 = 2u.toUByte().<!EVALUATED{IR}("2")!>or(2u.toUByte())<!>
72-
val or3 = 3u.toUByte().<!EVALUATED{IR}("3")!>or(2u.toUByte())<!>
73-
val or4 = 12u.toUByte().<!EVALUATED{IR}("14")!>or(10u.toUByte())<!>
74-
75-
val xor1 = 1u.toUByte().<!EVALUATED{IR}("3")!>xor(2u.toUByte())<!>
76-
val xor2 = 2u.toUByte().<!EVALUATED{IR}("0")!>xor(2u.toUByte())<!>
77-
val xor3 = 3u.toUByte().<!EVALUATED{IR}("1")!>xor(2u.toUByte())<!>
78-
val xor4 = 12u.toUByte().<!EVALUATED{IR}("6")!>xor(10u.toUByte())<!>
79-
80-
val inv1 = 0u.toUByte().<!EVALUATED{IR}("255")!>inv()<!>
81-
val inv2 = 1u.toUByte().<!EVALUATED{IR}("254")!>inv()<!>
82-
83-
val convert1 = 1u.toUByte().<!EVALUATED{IR}("1")!>toUByte()<!>
84-
val convert2 = 1u.toUByte().<!EVALUATED{IR}("1")!>toUShort()<!>
85-
val convert3 = 1u.toUByte().<!EVALUATED{IR}("1")!>toUInt()<!>
86-
val convert4 = 1u.toUByte().<!EVALUATED{IR}("1")!>toULong()<!>
87-
val convert5 = 1u.toUByte().<!EVALUATED{IR}("1.0")!>toFloat()<!>
88-
val convert6 = 1u.toUByte().<!EVALUATED{IR}("1.0")!>toDouble()<!>
89-
val convert7 = 1u.toUByte().<!EVALUATED{IR}("1")!>toByte()<!>
90-
val convert8 = 1u.toUByte().<!EVALUATED{IR}("1")!>toShort()<!>
91-
val convert9 = 1u.toUByte().<!EVALUATED{IR}("1")!>toInt()<!>
92-
val convert10 = 1u.toUByte().<!EVALUATED{IR}("1")!>toLong()<!>
93-
val convert11 = 1.<!EVALUATED{IR}("1")!>toByte()<!>.toUByte()
94-
val convert12 = 1.<!EVALUATED{IR}("1")!>toShort()<!>.toUByte()
95-
val convert13 = 1.toUByte()
96-
val convert14 = 1L.toUByte()
97-
98-
val equals1 = <!EVALUATED{IR}("false")!>1u.toUByte() == 2u.toUByte()<!>
99-
val equals2 = <!EVALUATED{IR}("true")!>2u.toUByte() == 2u.toUByte()<!>
100-
val equals3 = <!EVALUATED{IR}("false")!>3u.toUByte() == 2u.toUByte()<!>
101-
val equals4 = <!EVALUATED{IR}("false")!>4u.toUByte() == 2u.toUByte()<!>
102-
103-
val toString1 = 1u.toUByte().<!EVALUATED{IR}("1")!>toString()<!>
104-
val toString2 = 2u.toUByte().<!EVALUATED{IR}("2")!>toString()<!>
105-
106-
val limits1 = <!EVALUATED{IR}("255")!>254u.toUByte()+1u.toUByte()<!>
107-
val limits2 = <!EVALUATED{IR}("256")!>255u.toUByte()+1u.toUByte()<!>
108-
val limits3 = <!EVALUATED{IR}("4294967295")!>0u.toUByte()-1u.toUByte()<!>
7+
const val compareTo1 = 1u.toUByte().<!EVALUATED("-1")!>compareTo(2u.toUByte())<!>
8+
const val compareTo2 = 2u.toUByte().<!EVALUATED("0")!>compareTo(2u.toUByte())<!>
9+
const val compareTo3 = 3u.toUByte().<!EVALUATED("1")!>compareTo(2u.toUByte())<!>
10+
const val compareTo4 = 2u.toUByte().<!EVALUATED("0")!>compareTo(2u.toUShort())<!>
11+
const val compareTo5 = 2u.toUByte().<!EVALUATED("0")!>compareTo(2u)<!>
12+
const val compareTo6 = 2u.toUByte().<!EVALUATED("0")!>compareTo(2UL)<!>
13+
14+
const val plus1 = 1u.toUByte().<!EVALUATED("3")!>plus(2u.toUByte())<!>
15+
const val plus2 = 2u.toUByte().<!EVALUATED("4")!>plus(2u.toUByte())<!>
16+
const val plus3 = 3u.toUByte().<!EVALUATED("5")!>plus(2u.toUByte())<!>
17+
const val plus4 = 2u.toUByte().<!EVALUATED("4")!>plus(2u.toUShort())<!>
18+
const val plus5 = 2u.toUByte().<!EVALUATED("4")!>plus(2u)<!>
19+
const val plus6 = 2u.toUByte().<!EVALUATED("4")!>plus(2UL)<!>
20+
21+
const val minus1 = 1u.toUByte().<!EVALUATED("4294967295")!>minus(2u.toUByte())<!>
22+
const val minus2 = 2u.toUByte().<!EVALUATED("0")!>minus(2u.toUByte())<!>
23+
const val minus3 = 3u.toUByte().<!EVALUATED("1")!>minus(2u.toUByte())<!>
24+
const val minus4 = 2u.toUByte().<!EVALUATED("0")!>minus(2u.toUShort())<!>
25+
const val minus5 = 2u.toUByte().<!EVALUATED("0")!>minus(2u)<!>
26+
const val minus6 = 2u.toUByte().<!EVALUATED("0")!>minus(2UL)<!>
27+
28+
const val times1 = 1u.toUByte().<!EVALUATED("2")!>times(2u.toUByte())<!>
29+
const val times2 = 2u.toUByte().<!EVALUATED("4")!>times(2u.toUByte())<!>
30+
const val times3 = 3u.toUByte().<!EVALUATED("6")!>times(2u.toUByte())<!>
31+
const val times4 = 2u.toUByte().<!EVALUATED("4")!>times(2u.toUShort())<!>
32+
const val times5 = 2u.toUByte().<!EVALUATED("4")!>times(2u)<!>
33+
const val times6 = 2u.toUByte().<!EVALUATED("4")!>times(2UL)<!>
34+
35+
const val div1 = 1u.toUByte().<!EVALUATED("0")!>div(2u.toUByte())<!>
36+
const val div2 = 2u.toUByte().<!EVALUATED("1")!>div(2u.toUByte())<!>
37+
const val div3 = 3u.toUByte().<!EVALUATED("1")!>div(2u.toUByte())<!>
38+
const val div4 = 2u.toUByte().<!EVALUATED("1")!>div(2u.toUShort())<!>
39+
const val div5 = 2u.toUByte().<!EVALUATED("1")!>div(2u)<!>
40+
const val div6 = 2u.toUByte().<!EVALUATED("1")!>div(2UL)<!>
41+
42+
const val floorDiv1 = 1u.toUByte().<!EVALUATED("0")!>floorDiv(2u.toUByte())<!>
43+
const val floorDiv2 = 2u.toUByte().<!EVALUATED("1")!>floorDiv(2u.toUByte())<!>
44+
const val floorDiv3 = 3u.toUByte().<!EVALUATED("1")!>floorDiv(2u.toUByte())<!>
45+
const val floorDiv4 = 2u.toUByte().<!EVALUATED("1")!>floorDiv(2u.toUShort())<!>
46+
const val floorDiv5 = 2u.toUByte().<!EVALUATED("1")!>floorDiv(2u)<!>
47+
const val floorDiv6 = 2u.toUByte().<!EVALUATED("1")!>floorDiv(2UL)<!>
48+
49+
const val rem1 = 1u.toUByte().<!EVALUATED("1")!>rem(2u.toUByte())<!>
50+
const val rem2 = 2u.toUByte().<!EVALUATED("0")!>rem(2u.toUByte())<!>
51+
const val rem3 = 3u.toUByte().<!EVALUATED("1")!>rem(2u.toUByte())<!>
52+
const val rem4 = 2u.toUByte().<!EVALUATED("0")!>rem(2u.toUShort())<!>
53+
const val rem5 = 2u.toUByte().<!EVALUATED("0")!>rem(2u)<!>
54+
const val rem6 = 2u.toUByte().<!EVALUATED("0")!>rem(2UL)<!>
55+
56+
const val mod1 = 1u.toUByte().<!EVALUATED("1")!>mod(2u.toUByte())<!>
57+
const val mod2 = 2u.toUByte().<!EVALUATED("0")!>mod(2u.toUByte())<!>
58+
const val mod3 = 3u.toUByte().<!EVALUATED("1")!>mod(2u.toUByte())<!>
59+
const val mod4 = 2u.toUByte().<!EVALUATED("0")!>mod(2u.toUShort())<!>
60+
const val mod5 = 2u.toUByte().<!EVALUATED("0")!>mod(2u)<!>
61+
const val mod6 = 2u.toUByte().<!EVALUATED("0")!>mod(2UL)<!>
62+
63+
const val and1 = 1u.toUByte().<!EVALUATED("0")!>and(2u.toUByte())<!>
64+
const val and2 = 2u.toUByte().<!EVALUATED("2")!>and(2u.toUByte())<!>
65+
const val and3 = 3u.toUByte().<!EVALUATED("2")!>and(2u.toUByte())<!>
66+
const val and4 = 12u.toUByte().<!EVALUATED("8")!>and(10u.toUByte())<!>
67+
68+
const val or1 = 1u.toUByte().<!EVALUATED("3")!>or(2u.toUByte())<!>
69+
const val or2 = 2u.toUByte().<!EVALUATED("2")!>or(2u.toUByte())<!>
70+
const val or3 = 3u.toUByte().<!EVALUATED("3")!>or(2u.toUByte())<!>
71+
const val or4 = 12u.toUByte().<!EVALUATED("14")!>or(10u.toUByte())<!>
72+
73+
const val xor1 = 1u.toUByte().<!EVALUATED("3")!>xor(2u.toUByte())<!>
74+
const val xor2 = 2u.toUByte().<!EVALUATED("0")!>xor(2u.toUByte())<!>
75+
const val xor3 = 3u.toUByte().<!EVALUATED("1")!>xor(2u.toUByte())<!>
76+
const val xor4 = 12u.toUByte().<!EVALUATED("6")!>xor(10u.toUByte())<!>
77+
78+
const val inv1 = 0u.toUByte().<!EVALUATED("255")!>inv()<!>
79+
const val inv2 = 1u.toUByte().<!EVALUATED("254")!>inv()<!>
80+
81+
const val convert1 = 1u.toUByte().<!EVALUATED("1")!>toUByte()<!>
82+
const val convert2 = 1u.toUByte().<!EVALUATED("1")!>toUShort()<!>
83+
const val convert3 = 1u.toUByte().<!EVALUATED("1")!>toUInt()<!>
84+
const val convert4 = 1u.toUByte().<!EVALUATED("1")!>toULong()<!>
85+
const val convert5 = 1u.toUByte().<!EVALUATED("1.0")!>toFloat()<!>
86+
const val convert6 = 1u.toUByte().<!EVALUATED("1.0")!>toDouble()<!>
87+
const val convert7 = 1u.toUByte().<!EVALUATED("1")!>toByte()<!>
88+
const val convert8 = 1u.toUByte().<!EVALUATED("1")!>toShort()<!>
89+
const val convert9 = 1u.toUByte().<!EVALUATED("1")!>toInt()<!>
90+
const val convert10 = 1u.toUByte().<!EVALUATED("1")!>toLong()<!>
91+
92+
// TODO, KT-80646: Enable once conversion extension functions are supported (requires bootstrapped compiler)
93+
// const val convert11 = 1.toByte().toUByte()
94+
// const val convert12 = 1.toShort().toUByte()
95+
// const val convert13 = 1.toUByte()
96+
// const val convert14 = 1L.toUByte()
97+
98+
const val equals1 = <!EVALUATED("false")!>1u.toUByte() == 2u.toUByte()<!>
99+
const val equals2 = <!EVALUATED("true")!>2u.toUByte() == 2u.toUByte()<!>
100+
const val equals3 = <!EVALUATED("false")!>3u.toUByte() == 2u.toUByte()<!>
101+
const val equals4 = <!EVALUATED("false")!>4u.toUByte() == 2u.toUByte()<!>
102+
103+
const val toString1 = 1u.toUByte().<!EVALUATED("1")!>toString()<!>
104+
const val toString2 = 2u.toUByte().<!EVALUATED("2")!>toString()<!>
105+
106+
const val limits1 = <!EVALUATED("255")!>254u.toUByte()+1u.toUByte()<!>
107+
const val limits2 = <!EVALUATED("256")!>255u.toUByte()+1u.toUByte()<!>
108+
const val limits3 = <!EVALUATED("4294967295")!>0u.toUByte()-1u.toUByte()<!>
109109

110110
// STOP_EVALUATION_CHECKS
111111
fun box(): String {
@@ -193,10 +193,10 @@ fun box(): String {
193193
if (convert8.id() != 1.toShort()) return "Fail convert8"
194194
if (convert9.id() != 1) return "Fail convert9"
195195
if (convert10.id() != 1L) return "Fail convert10"
196-
if (convert11.id() != 1u.toUByte()) return "Fail convert11"
197-
if (convert12.id() != 1u.toUByte()) return "Fail convert12"
198-
if (convert13.id() != 1u.toUByte()) return "Fail convert13"
199-
if (convert14.id() != 1u.toUByte()) return "Fail convert14"
196+
// if (convert11.id() != 1u.toUByte()) return "Fail convert11"
197+
// if (convert12.id() != 1u.toUByte()) return "Fail convert12"
198+
// if (convert13.id() != 1u.toUByte()) return "Fail convert13"
199+
// if (convert14.id() != 1u.toUByte()) return "Fail convert14"
200200

201201
if (equals1.id() != false) return "Fail equals1"
202202
if (equals2.id() != true) return "Fail equals2"

0 commit comments

Comments
 (0)