From 694864ae769d329e5df3410dad40cfc4ce9a205a Mon Sep 17 00:00:00 2001 From: Pavel Kunyavskiy Date: Thu, 15 Jul 2021 17:11:28 +0300 Subject: [PATCH] [K/N] Support kType generation as ConstantValue --- .../jetbrains/kotlin/backend/konan/ir/Ir.kt | 4 +- .../backend/konan/llvm/IntrinsicGenerator.kt | 15 -- .../backend/konan/lower/PostInlineLowering.kt | 22 ++- .../backend/konan/lower/ReflectionSupport.kt | 181 +++++++++--------- .../kotlin/native/internal/ArrayAsList.kt | 15 ++ .../kotlin/native/internal/IntrinsicType.kt | 1 - .../kotlin/native/internal/KClassImpl.kt | 4 - .../kotlin/native/internal/KTypeImpl.kt | 51 ++++- .../native/internal/KTypeParameterImpl.kt | 8 +- 9 files changed, 175 insertions(+), 126 deletions(-) create mode 100644 kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/ArrayAsList.kt diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index 7e26c33d416..904590e0e45 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -442,7 +442,6 @@ internal class KonanSymbols( return symbolTable.referenceEnumEntry(descriptor) } - val getClassTypeInfo = internalFunction("getClassTypeInfo") val getObjectTypeInfo = internalFunction("getObjectTypeInfo") val kClassImpl = internalClass("KClassImpl") val kClassImplConstructor by lazy { kClassImpl.constructors.single { it.descriptor.isPrimary } } @@ -453,6 +452,7 @@ internal class KonanSymbols( val kTypeImpl = internalClass("KTypeImpl") val kTypeImplIntrinsicConstructor by lazy { kTypeImpl.constructors.single { it.descriptor.valueParameters.isEmpty() } } val kTypeImplForTypeParametersWithRecursiveBounds = internalClass("KTypeImplForTypeParametersWithRecursiveBounds") + val kTypeProjectionList = internalClass("KTypeProjectionList") val kTypeProjection = symbolTable.referenceClass(context.reflectionTypes.kTypeProjection) @@ -484,6 +484,8 @@ internal class KonanSymbols( val listOf = irBuiltIns.findFunctions(Name.identifier("listOf"), "kotlin", "collections") .single { it.descriptor.valueParameters.size == 1 && it.descriptor.valueParameters[0].isVararg } + val arrayAsList = internalClass("ArrayAsList") + val threadLocal = symbolTable.referenceClass( context.builtIns.builtInsModule.findClassAcrossModuleDependencies( ClassId.topLevel(KonanFqNames.threadLocal))!!) diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt index c6684a249df..956bd586866 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt @@ -61,7 +61,6 @@ internal enum class IntrinsicType { OBJC_INIT_BY, OBJC_GET_SELECTOR, // Other - GET_CLASS_TYPE_INFO, CREATE_UNINITIALIZED_INSTANCE, IDENTITY, IMMUTABLE_BLOB, @@ -242,7 +241,6 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv IntrinsicType.OBJC_GET_MESSENGER_STRET -> emitObjCGetMessenger(args, isStret = true) IntrinsicType.OBJC_GET_OBJC_CLASS -> emitGetObjCClass(callSite) IntrinsicType.OBJC_CREATE_SUPER_STRUCT -> emitObjCCreateSuperStruct(args) - IntrinsicType.GET_CLASS_TYPE_INFO -> emitGetClassTypeInfo(callSite) IntrinsicType.INTEROP_READ_BITS -> emitReadBits(args) IntrinsicType.INTEROP_WRITE_BITS -> emitWriteBits(args) IntrinsicType.INTEROP_READ_PRIMITIVE -> emitReadPrimitive(callSite, args) @@ -432,19 +430,6 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv TODO("Implement me") } - private fun FunctionGenerationContext.emitGetClassTypeInfo(callSite: IrCall): LLVMValueRef { - val typeArgument = callSite.getTypeArgument(0)!! - val typeArgumentClass = typeArgument.getClass() - return if (typeArgumentClass == null) { - // Should not happen anymore, but it is safer to handle this case. - unreachable() - kNullInt8Ptr - } else { - val typeInfo = codegen.typeInfoValue(typeArgumentClass) - LLVMConstBitCast(typeInfo, kInt8Ptr)!! - } - } - private fun FunctionGenerationContext.emitObjCCreateSuperStruct(args: List): LLVMValueRef { assert(args.size == 2) val receiver = args[0] diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PostInlineLowering.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PostInlineLowering.kt index c60d5069870..8e78497eabd 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PostInlineLowering.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/PostInlineLowering.kt @@ -10,6 +10,8 @@ import org.jetbrains.kotlin.backend.common.ir.Symbols import org.jetbrains.kotlin.backend.common.lower.at import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.backend.konan.llvm.ConstantConstructorIntrinsicType +import org.jetbrains.kotlin.backend.konan.llvm.tryGetConstantConstructorIntrinsicType import org.jetbrains.kotlin.backend.konan.renderCompilerError import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope import org.jetbrains.kotlin.ir.declarations.IrDeclaration @@ -93,17 +95,23 @@ internal class PostInlineLowering(val context: Context) : BodyLoweringPass { expression.startOffset, expression.endOffset, context.irBuiltIns.stringType, IrConstKind.String, builder.toString())) - } else if (Symbols.isTypeOfIntrinsic(expression.symbol)) { - // Inline functions themselves are not called (they have been inlined at all call sites), - // so it is ok not to build exact type parameters for them. - val needExactTypeParameters = (container as? IrSimpleFunction)?.isInline != true - return with (KTypeGenerator(context, irFile, expression, needExactTypeParameters)) { - data.at(expression).irKType(expression.getTypeArgument(0)!!, leaveReifiedForLater = false) - } } return expression } + + override fun visitConstantObject(expression: IrConstantObject, data: IrBuilderWithScope): IrConstantValue { + return if (tryGetConstantConstructorIntrinsicType(expression.constructor) == ConstantConstructorIntrinsicType.KTYPE_IMPL) { + // Inline functions themselves are not called (they have been inlined at all call sites), + // so it is ok not to build exact type parameters for them. + val needExactTypeParameters = (container as? IrSimpleFunction)?.isInline != true + with(KTypeGenerator(context, irFile, expression, needExactTypeParameters)) { + data.at(expression).irKType(expression.typeArguments[0], leaveReifiedForLater = false) + } + } else + super.visitConstantObject(expression, data) + } + }, data = context.createIrBuilder((container as IrSymbolOwner).symbol, irBody.startOffset, irBody.endOffset)) } } \ No newline at end of file diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ReflectionSupport.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ReflectionSupport.kt index 07d1bb10214..1de422a087d 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ReflectionSupport.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/ReflectionSupport.kt @@ -8,30 +8,26 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.konan.InteropFqNames import org.jetbrains.kotlin.backend.konan.KonanBackendContext import org.jetbrains.kotlin.backend.konan.ir.typeWithStarProjections -import org.jetbrains.kotlin.backend.konan.ir.typeWithoutArguments import org.jetbrains.kotlin.backend.konan.isObjCClass import org.jetbrains.kotlin.backend.konan.llvm.computeFullName import org.jetbrains.kotlin.backend.konan.reportCompilationError import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.declarations.IrEnumEntry -import org.jetbrains.kotlin.ir.declarations.IrFile -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrTypeParameter -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression -import org.jetbrains.kotlin.ir.expressions.impl.IrGetEnumValueImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* -import org.jetbrains.kotlin.ir.util.irCall import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers import org.jetbrains.kotlin.types.Variance +private fun IrBuilderWithScope.irConstantString(string: String) = irConstantPrimitive(irString(string)) +private fun IrBuilderWithScope.irConstantInt(int: Int) = irConstantPrimitive(irInt(int)) +private fun IrBuilderWithScope.irConstantBoolean(boolean: Boolean) = irConstantPrimitive(irBoolean(boolean)) + internal class KTypeGenerator( val context: KonanBackendContext, val irFile: IrFile, @@ -49,15 +45,16 @@ internal class KTypeGenerator( type: IrType, leaveReifiedForLater: Boolean, seenTypeParameters: MutableSet - ): IrExpression { + ): IrConstantValue { if (type !is IrSimpleType) { // Represent as non-denotable type: return irKTypeImpl( - kClassifier = irNull(), - irTypeArguments = emptyList(), - isMarkedNullable = false, - leaveReifiedForLater = leaveReifiedForLater, - seenTypeParameters = seenTypeParameters + kClassifier = irConstantPrimitive(irNull()), + irTypeArguments = emptyList(), + isMarkedNullable = false, + leaveReifiedForLater = leaveReifiedForLater, + seenTypeParameters = seenTypeParameters, + type = type, ) } try { @@ -66,7 +63,7 @@ internal class KTypeGenerator( is IrTypeParameterSymbol -> { if (classifier.owner.isReified && leaveReifiedForLater) { // Leave as is for reification. - return irCall(symbols.typeOf).apply { putTypeArgument(0, type) } + return irConstantObject(symbols.kTypeImplIntrinsicConstructor, emptyList(), listOf(type)) } // Leave upper bounds of non-reified type parameters as is, even if they are reified themselves. @@ -80,26 +77,28 @@ internal class KTypeGenerator( irTypeArguments = type.arguments, isMarkedNullable = type.hasQuestionMark, leaveReifiedForLater = leaveReifiedForLater, - seenTypeParameters = seenTypeParameters + seenTypeParameters = seenTypeParameters, + type = type, ) } catch (t: RecursiveBoundsException) { if (needExactTypeParameters) this@KTypeGenerator.context.reportCompilationError(t.message!!, irFile, irElement) - return irCall(symbols.kTypeImplForTypeParametersWithRecursiveBounds.constructors.single()) + return irConstantObject(symbols.kTypeImplForTypeParametersWithRecursiveBounds.owner, emptyMap()) } } private fun IrBuilderWithScope.irKTypeImpl( - kClassifier: IrExpression, - irTypeArguments: List, - isMarkedNullable: Boolean, - leaveReifiedForLater: Boolean, - seenTypeParameters: MutableSet - ): IrExpression = irCall(symbols.kTypeImpl.constructors.single()).apply { - putValueArgument(0, kClassifier) - putValueArgument(1, irKTypeProjectionsList(irTypeArguments, leaveReifiedForLater, seenTypeParameters)) - putValueArgument(2, irBoolean(isMarkedNullable)) - } + kClassifier: IrConstantValue, + irTypeArguments: List, + isMarkedNullable: Boolean, + leaveReifiedForLater: Boolean, + seenTypeParameters: MutableSet, + type: IrType, + ): IrConstantValue = irConstantObject(symbols.kTypeImpl.owner, mapOf( + "classifier" to kClassifier, + "arguments" to irKTypeProjectionsList(irTypeArguments, leaveReifiedForLater, seenTypeParameters), + "isMarkedNullable" to irConstantPrimitive(irBoolean(isMarkedNullable)), + ), listOf(type)) private fun IrBuilderWithScope.irKClass(symbol: IrClassSymbol) = irKClass(this@KTypeGenerator.context, symbol) @@ -107,86 +106,80 @@ internal class KTypeGenerator( typeParameter: IrTypeParameter, leaveReifiedForLater: Boolean, seenTypeParameters: MutableSet - ): IrMemberAccessExpression<*> { + ): IrConstantValue { if (!seenTypeParameters.add(typeParameter)) throw RecursiveBoundsException("Non-reified type parameters with recursive bounds are not supported yet: ${typeParameter.render()}") - val result = irCall(symbols.kTypeParameterImpl.constructors.single()).apply { - putValueArgument(0, irString(typeParameter.name.asString())) - putValueArgument(1, irString(typeParameter.parentUniqueName)) - putValueArgument(2, irKTypeList(typeParameter.superTypes, leaveReifiedForLater, seenTypeParameters)) - putValueArgument(3, irKVariance(typeParameter.variance)) - putValueArgument(4, irBoolean(typeParameter.isReified)) - } + val result = irConstantObject(symbols.kTypeParameterImpl.owner, mapOf( + "name" to irConstantString(typeParameter.name.asString()), + "containerFqName" to irConstantString(typeParameter.parentUniqueName), + "upperBounds" to irKTypeList(typeParameter.superTypes, leaveReifiedForLater, seenTypeParameters), + "varianceId" to irConstantInt(mapVariance(typeParameter.variance)), + "isReified" to irConstantBoolean(typeParameter.isReified), + )) seenTypeParameters.remove(typeParameter) return result } - private val IrTypeParameter.parentUniqueName get() = when (val parent = parent) { - is IrFunction -> parent.computeFullName() - else -> parent.fqNameForIrSerialization.asString() - } - - private fun IrBuilderWithScope.irKVariance(variance: Variance) = - IrGetEnumValueImpl( - startOffset, endOffset, - symbols.kVariance.defaultType, - when (variance) { - Variance.INVARIANT -> symbols.kVarianceInvariant - Variance.IN_VARIANCE -> symbols.kVarianceIn - Variance.OUT_VARIANCE -> symbols.kVarianceOut - } - ) - - private fun IrBuilderWithScope.irKTypeLikeList( - types: List, - itemType: IrType, - itemBuilder: (T) -> IrExpression - ) = if (types.isEmpty()) { - irCall(symbols.emptyList, listOf(itemType)) - } else { - irCall(symbols.listOf, listOf(itemType)).apply { - putValueArgument(0, IrVarargImpl( - startOffset, endOffset, - type = symbols.array.typeWith(itemType), - varargElementType = itemType, - elements = types.map { itemBuilder(it) } - )) + private val IrTypeParameter.parentUniqueName + get() = when (val parent = parent) { + is IrFunction -> parent.computeFullName() + else -> parent.fqNameForIrSerialization.asString() } - } private fun IrBuilderWithScope.irKTypeList( types: List, leaveReifiedForLater: Boolean, seenTypeParameters: MutableSet - ) = irKTypeLikeList(types, symbols.kType.defaultType) { irKType(it, leaveReifiedForLater, seenTypeParameters) } + ): IrConstantValue { + val itemType = symbols.kType.defaultType + val elements = irConstantArray(symbols.array.typeWith(itemType), + types.map { irKType(it, leaveReifiedForLater, seenTypeParameters) } + ) + return irConstantObject(symbols.arrayAsList.owner, mapOf( + "array" to elements + )) + } + + // this constants are copypasted from KVarianceMapper.Companion in KTypeImpl.kt + private fun mapVariance(variance: Variance) = when (variance) { + Variance.INVARIANT -> 0 + Variance.IN_VARIANCE -> 1 + Variance.OUT_VARIANCE -> 2 + } private fun IrBuilderWithScope.irKTypeProjectionsList( irTypeArguments: List, leaveReifiedForLater: Boolean, seenTypeParameters: MutableSet - ) = irKTypeLikeList(irTypeArguments, symbols.kTypeProjection.typeWithoutArguments) { - irKTypeProjection(it, leaveReifiedForLater, seenTypeParameters) - } - - private fun IrBuilderWithScope.irKTypeProjection( - argument: IrTypeArgument, - leaveReifiedForLater: Boolean, - seenTypeParameters: MutableSet - ) = when (argument) { - is IrTypeProjection -> irCall(symbols.kTypeProjectionFactories.getValue(argument.variance)).apply { - dispatchReceiver = irGetObject(symbols.kTypeProjectionCompanion) - putValueArgument(0, irKType(argument.type, leaveReifiedForLater, seenTypeParameters)) - } - - is IrStarProjection -> irCall(symbols.kTypeProjectionStar.owner.getter!!).apply { - dispatchReceiver = irGetObject(symbols.kTypeProjectionCompanion) - } - - else -> error("Unexpected IrTypeArgument: $argument (${argument::class})") + ): IrConstantValue { + val variance = irConstantArray( + symbols.intArrayType, + irTypeArguments.map { argument -> + when (argument) { + is IrStarProjection -> irConstantInt(-1) + is IrTypeProjection -> irConstantInt(mapVariance(argument.variance)) + else -> error("Unexpected IrTypeArgument: $argument (${argument::class})") + } + }) + val type = irConstantArray( + symbols.array.typeWith(symbols.kType.defaultType.makeNullable()), + irTypeArguments.map { argument -> + when (argument) { + is IrStarProjection -> irConstantPrimitive(irNull()) + is IrTypeProjection -> irKType(argument.type, leaveReifiedForLater, seenTypeParameters) + else -> error("Unexpected IrTypeArgument: $argument (${argument::class})") + } + }) + return irConstantObject( + symbols.kTypeProjectionList.owner, + mapOf( + "variance" to variance, + "type" to type + )) } } -internal fun IrBuilderWithScope.irKClass(context: KonanBackendContext, symbol: IrClassSymbol): IrExpression { +internal fun IrBuilderWithScope.irKClass(context: KonanBackendContext, symbol: IrClassSymbol): IrConstantValue { val symbols = context.ir.symbols return when { symbol.descriptor.isObjCClass() -> @@ -196,13 +189,11 @@ internal fun IrBuilderWithScope.irKClass(context: KonanBackendContext, symbol: I it is ClassDescriptor && it.fqNameUnsafe == InteropFqNames.nativePointed } -> irKClassUnsupported(context, "KClass for interop types is not supported yet") - else -> irCall(symbols.kClassImplConstructor.owner).apply { - putValueArgument(0, irCall(symbols.getClassTypeInfo, listOf(symbol.typeWithStarProjections))) - } + else -> irConstantObject(symbols.kClassImplIntrinsicConstructor, emptyList(), listOf(symbol.typeWithStarProjections)) } } private fun IrBuilderWithScope.irKClassUnsupported(context: KonanBackendContext, message: String) = - irCall(context.ir.symbols.kClassUnsupportedImplConstructor.owner).apply { - putValueArgument(0, irString(message)) - } + irConstantObject(context.ir.symbols.kClassUnsupportedImpl.owner, mapOf( + "message" to irConstantString(message) + )) diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/ArrayAsList.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/ArrayAsList.kt new file mode 100644 index 00000000000..151a8abc066 --- /dev/null +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/ArrayAsList.kt @@ -0,0 +1,15 @@ +/* + * 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. + */ + +package kotlin.native.internal + +class ArrayAsList(val array: Array) : AbstractList(), RandomAccess { + override val size: Int get() = array.size + override fun isEmpty(): Boolean = array.isEmpty() + override fun contains(element: T): Boolean = array.contains(element) + override fun get(index: Int): T = array[index] + override fun indexOf(element: T): Int = array.indexOf(element) + override fun lastIndexOf(element: T): Int = array.lastIndexOf(element) +} \ No newline at end of file diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/IntrinsicType.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/IntrinsicType.kt index 4fc12f916ae..64be3c59b71 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/IntrinsicType.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/IntrinsicType.kt @@ -46,7 +46,6 @@ class IntrinsicType { const val OBJC_GET_SELECTOR = "OBJC_GET_SELECTOR" // Other - const val GET_CLASS_TYPE_INFO = "GET_CLASS_TYPE_INFO" const val INTEROP_READ_BITS = "INTEROP_READ_BITS" const val INTEROP_WRITE_BITS = "INTEROP_WRITE_BITS" const val CREATE_UNINITIALIZED_INSTANCE = "CREATE_UNINITIALIZED_INSTANCE" diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KClassImpl.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KClassImpl.kt index e15f3833538..0b06ec4ebf1 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KClassImpl.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KClassImpl.kt @@ -78,10 +78,6 @@ private external fun findAssociatedObjectImpl(typeInfo: NativePtr, key: NativePt @GCUnsafeCall("Kotlin_Any_getTypeInfo") internal external fun getObjectTypeInfo(obj: Any): NativePtr -@ExportForCompiler -@TypedIntrinsic(IntrinsicType.GET_CLASS_TYPE_INFO) -internal external inline fun getClassTypeInfo(): NativePtr - @GCUnsafeCall("Kotlin_TypeInfo_getPackageName") private external fun getPackageName(typeInfo: NativePtr, checkFlags: Boolean): String? diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KTypeImpl.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KTypeImpl.kt index cf3185cd44d..64bfe938a61 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KTypeImpl.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KTypeImpl.kt @@ -7,13 +7,60 @@ package kotlin.native.internal import kotlin.reflect.* -internal class KTypeImpl( +internal object KVarianceMapper { + // this constants are copypasted to ReflectionSupport.kt + const val VARIANCE_STAR = -1 + const val VARIANCE_INVARIANT = 0 + const val VARIANCE_IN = 1 + const val VARIANCE_OUT = 2 + + fun idByVariance(variance: KVariance) = when (variance) { + KVariance.INVARIANT -> VARIANCE_INVARIANT + KVariance.IN -> VARIANCE_IN + KVariance.OUT -> VARIANCE_OUT + } + + fun varianceById(id: Int) = when (id) { + VARIANCE_STAR -> null + VARIANCE_INVARIANT -> KVariance.INVARIANT + VARIANCE_IN -> KVariance.IN + VARIANCE_OUT -> KVariance.OUT + else -> throw IllegalStateException("Unknown variance id ${id}") + } +} + +/* + * This class is used to avoid having enum inside KType class + * Static initialization for enum objects is not supported yet, + * so to initialize KType statically we need to avoid them. + * + * When this issue is resolved, this class can be replaced with just ArrayList + */ +internal class KTypeProjectionList(val variance: IntArray, val type: Array) : AbstractList() { + override val size + get() = variance.size + + + override fun get(index: Int) : KTypeProjection { + AbstractList.checkElementIndex(index, size) + val kVariance = KVarianceMapper.varianceById(variance[index]) ?: return KTypeProjection.STAR + return KTypeProjection(kVariance, type[index]) + } + +} + +internal class KTypeImpl( override val classifier: KClassifier?, override val arguments: List, override val isMarkedNullable: Boolean ) : KType { + + @ExportForCompiler + @ConstantConstructorIntrinsic("KTYPE_IMPL") + constructor() : this(null, TODO("This is intrinsic constructor and it shouldn't be used directly"), false) + override fun equals(other: Any?) = - other is KTypeImpl && + other is KTypeImpl<*> && this.classifier == other.classifier && this.arguments == other.arguments && this.isMarkedNullable == other.isMarkedNullable diff --git a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KTypeParameterImpl.kt b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KTypeParameterImpl.kt index f7fe3b74877..c4d80d72d77 100644 --- a/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KTypeParameterImpl.kt +++ b/kotlin-native/runtime/src/main/kotlin/kotlin/native/internal/KTypeParameterImpl.kt @@ -11,9 +11,15 @@ internal class KTypeParameterImpl( override val name: String, private val containerFqName: String, override val upperBounds: List, - override val variance: KVariance, + val varianceId: Int, // mapping is used to make static initialization possible override val isReified: Boolean ) : KTypeParameter { + override val variance: KVariance + get() = KVarianceMapper.varianceById(varianceId)!! + + constructor(name: String, containerFqName: String, upperBounds: List, variance: KVariance, isReified: Boolean) : + this(name, containerFqName, upperBounds, KVarianceMapper.idByVariance(variance), isReified) + override fun toString(): String = when (variance) { KVariance.INVARIANT -> "" KVariance.IN -> "in "