[FIR] Support for constructor calls of unsigned types in constants
This commit is contained in:
committed by
TeamCityServer
parent
f9eba6e842
commit
7f2eaab02b
+4
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.name.StandardClassIds.primitiveArrayTypeByElementType
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.StandardClassIds.unsignedArrayTypeByElementType
|
||||
|
||||
object FirAnnotationClassDeclarationChecker : FirRegularClassChecker() {
|
||||
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
@@ -84,6 +85,9 @@ object FirAnnotationClassDeclarationChecker : FirRegularClassChecker() {
|
||||
classId in primitiveArrayTypeByElementType.values -> {
|
||||
// DO NOTHING: primitive arrays are allowed
|
||||
}
|
||||
classId in unsignedArrayTypeByElementType.values -> {
|
||||
// DO NOTHING: arrays of unsigned types are allowed
|
||||
}
|
||||
classId == StandardClassIds.Array -> {
|
||||
if (!isAllowedArray(typeRef, context.session))
|
||||
reporter.reportOn(typeRef.source, FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER, context)
|
||||
|
||||
+1
@@ -46,6 +46,7 @@ class IrCompileTimeChecker(
|
||||
parentType?.isString() == true -> (this as IrDeclarationWithName).name.asString() !in setOf("subSequence", "hashCode")
|
||||
parentType?.isAny() == true -> (this as IrFunction).name.asString() == "toString" && expression?.dispatchReceiver !is IrGetObjectValue
|
||||
parent?.isObject == true -> parent.parentClassOrNull?.defaultType?.let { it.isPrimitiveType() || it.isUnsignedType() } == true
|
||||
parentType?.isUnsignedType() == true && (this is IrConstructor) -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,6 +379,10 @@ class IrInterpreter(private val irBuiltIns: IrBuiltIns, private val bodyMap: Map
|
||||
.apply { stack.peekReturnValue().addTypeArguments(typeArguments) }
|
||||
}
|
||||
|
||||
if (irClass.defaultType.isUnsignedType()) {
|
||||
return stack.newFrame(initPool = valueArguments) { handleIntrinsicMethods(owner) }
|
||||
}
|
||||
|
||||
val state = Common(irClass).apply { this.addTypeArguments(typeArguments) }
|
||||
if (irClass.isLocal) state.fields.addAll(stack.getAll()) // TODO save only necessary declarations
|
||||
if (irClass.isInner) {
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ internal class IntrinsicEvaluator {
|
||||
EnumHashCode.equalTo(irFunction) -> EnumHashCode.evaluate(irFunction, stack, interpret)
|
||||
JsPrimitives.equalTo(irFunction) -> JsPrimitives.evaluate(irFunction, stack, interpret)
|
||||
ArrayConstructor.equalTo(irFunction) -> ArrayConstructor.evaluate(irFunction, stack, interpret)
|
||||
UnsignedConstructor.equalTo(irFunction) -> UnsignedConstructor.evaluate(irFunction, stack, interpret)
|
||||
else -> throw InterpreterMethodNotFoundException("Method ${irFunction.name} hasn't implemented")
|
||||
}
|
||||
}
|
||||
|
||||
+23
@@ -5,15 +5,20 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.interpreter.intrinsics
|
||||
|
||||
import org.jetbrains.kotlin.builtins.UnsignedType
|
||||
import org.jetbrains.kotlin.ir.interpreter.*
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Stack
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.interpreter.state.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.getUnsignedType
|
||||
import org.jetbrains.kotlin.ir.types.isUnsignedType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
|
||||
internal sealed class IntrinsicBase {
|
||||
@@ -189,4 +194,22 @@ internal object ArrayConstructor : IntrinsicBase() {
|
||||
stack.pushReturnValue(arrayValue.toPrimitiveStateArray(irFunction.parentAsClass.defaultType))
|
||||
return Next
|
||||
}
|
||||
}
|
||||
|
||||
internal object UnsignedConstructor : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val constructorCall = irFunction as? IrConstructor ?: return false
|
||||
val irClass = constructorCall.parent as IrClass
|
||||
return irClass.defaultType.isUnsignedType() && irFunction.valueParameters.size == 1
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, stack: Stack, interpret: IrElement.() -> ExecutionResult): ExecutionResult {
|
||||
val parameter = irFunction.valueParameters.single()
|
||||
val argument = stack.getVariable(parameter.symbol).state.asNumber()
|
||||
val irClass = irFunction.parent as IrClass
|
||||
val result = Common(irClass)
|
||||
result.fields.add(Variable(parameter.symbol, argument.toState(parameter.type)))
|
||||
stack.pushReturnValue(result)
|
||||
return Next
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ internal interface State {
|
||||
|
||||
internal fun State.isNull() = this is Primitive<*> && this.value == null
|
||||
|
||||
internal fun State.asNumber() = (this as Primitive<*>).value as Number
|
||||
internal fun State.asInt() = (this as Primitive<*>).value as Int
|
||||
internal fun State.asBoolean() = (this as Primitive<*>).value as Boolean
|
||||
internal fun State.asString() = (this as Primitive<*>).value.toString()
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_BACKEND: NATIVE
|
||||
// WITH_RUNTIME
|
||||
// WITH_STDLIB
|
||||
|
||||
+8
-9
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// WITH_REFLECT
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
@@ -7,21 +6,21 @@ annotation class AnnoUS(val us: UShortArray)
|
||||
annotation class AnnoUI(val ui: UIntArray)
|
||||
annotation class AnnoUL(val ul: ULongArray)
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
const val ub0 = UByte(1)
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
const val us0 = UShort(2)
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
const val ul0 = ULong(3)
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
const val ui0 = UInt(-1)
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
const val ui1 = UInt(0)
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
const val ui2 = UInt(40 + 2)
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
object Foo {
|
||||
@AnnoUB([UByte(1), ub0])
|
||||
fun f0() {}
|
||||
@@ -41,7 +40,7 @@ fun <T> check(ann: Annotation, f: T.() -> Boolean) {
|
||||
if (!result) throw RuntimeException("fail for $ann")
|
||||
}
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER")
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
fun box(): String {
|
||||
if (ub0.toByte() != 1.toByte()) return "fail"
|
||||
if (us0.toShort() != 2.toShort()) return "fail"
|
||||
|
||||
+1
-2
@@ -1,11 +1,10 @@
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// WITH_REFLECT
|
||||
// TARGET_BACKEND: JVM
|
||||
|
||||
// TODO: it's not clear why compilation fails for Android
|
||||
// IGNORE_BACKEND: ANDROID
|
||||
|
||||
@file:Suppress("INVISIBLE_MEMBER")
|
||||
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
|
||||
annotation class AnnoUB(val ub0: UByte, val ub1: UByte)
|
||||
annotation class AnnoUS(val us0: UShort, val us1: UShort)
|
||||
|
||||
Reference in New Issue
Block a user