[IR] Supported non-reified typeOf
This commit is contained in:
+7
-7
@@ -268,13 +268,6 @@ internal val testProcessorPhase = makeKonanFileOpPhase(
|
||||
description = "Unit test processor"
|
||||
)
|
||||
|
||||
internal val enumClassPhase = makeKonanFileOpPhase(
|
||||
{ context, irFile -> EnumClassLowering(context).run(irFile) },
|
||||
name = "Enums",
|
||||
description = "Enum classes lowering",
|
||||
prerequisite = setOf(enumConstructorsPhase) // TODO: make weak dependency on `testProcessorPhase`
|
||||
)
|
||||
|
||||
internal val delegationPhase = makeKonanFileLoweringPhase(
|
||||
::PropertyDelegationLowering,
|
||||
name = "Delegation",
|
||||
@@ -288,6 +281,13 @@ internal val functionReferencePhase = makeKonanFileLoweringPhase(
|
||||
prerequisite = setOf(delegationPhase, localFunctionsPhase) // TODO: make weak dependency on `testProcessorPhase`
|
||||
)
|
||||
|
||||
internal val enumClassPhase = makeKonanFileOpPhase(
|
||||
{ context, irFile -> EnumClassLowering(context).run(irFile) },
|
||||
name = "Enums",
|
||||
description = "Enum classes lowering",
|
||||
prerequisite = setOf(enumConstructorsPhase, functionReferencePhase) // TODO: make weak dependency on `testProcessorPhase`
|
||||
)
|
||||
|
||||
internal val singleAbstractMethodPhase = makeKonanFileLoweringPhase(
|
||||
::NativeSingleAbstractMethodLowering,
|
||||
name = "SingleAbstractMethod",
|
||||
|
||||
+4
@@ -45,6 +45,8 @@ class KonanReflectionTypes(module: ModuleDescriptor, internalPackage: FqName) {
|
||||
val kMutableProperty1: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||
val kMutableProperty2: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||
val kTypeProjection: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||
val kType: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||
val kVariance: ClassDescriptor by ClassLookup(kotlinReflectScope)
|
||||
|
||||
val kFunctionImpl: ClassDescriptor by ClassLookup(internalScope)
|
||||
val kSuspendFunctionImpl: ClassDescriptor by ClassLookup(internalScope)
|
||||
@@ -56,4 +58,6 @@ class KonanReflectionTypes(module: ModuleDescriptor, internalPackage: FqName) {
|
||||
val kMutableProperty2Impl: ClassDescriptor by ClassLookup(internalScope)
|
||||
val kLocalDelegatedPropertyImpl: ClassDescriptor by ClassLookup(internalScope)
|
||||
val kLocalDelegatedMutablePropertyImpl: ClassDescriptor by ClassLookup(internalScope)
|
||||
|
||||
val typeOf = kotlinReflectScope.getContributedFunctions(Name.identifier("typeOf"), NoLookupLocation.FROM_REFLECTION).single()
|
||||
}
|
||||
|
||||
+8
-1
@@ -450,14 +450,21 @@ internal class KonanSymbols(
|
||||
|
||||
val kLocalDelegatedPropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedPropertyImpl)
|
||||
val kLocalDelegatedMutablePropertyImpl = symbolTable.referenceClass(context.reflectionTypes.kLocalDelegatedMutablePropertyImpl)
|
||||
|
||||
val typeOf = symbolTable.referenceSimpleFunction(context.reflectionTypes.typeOf)
|
||||
|
||||
val kType = symbolTable.referenceClass(context.reflectionTypes.kType)
|
||||
val kVariance = symbolTable.referenceClass(context.reflectionTypes.kVariance)
|
||||
|
||||
val getClassTypeInfo = internalFunction("getClassTypeInfo")
|
||||
val getObjectTypeInfo = internalFunction("getObjectTypeInfo")
|
||||
val kClassImpl = internalClass("KClassImpl")
|
||||
val kClassImplConstructor by lazy { kClassImpl.constructors.single() }
|
||||
val kClassUnsupportedImpl = internalClass("KClassUnsupportedImpl")
|
||||
val kClassUnsupportedImplConstructor by lazy { kClassUnsupportedImpl.constructors.single() }
|
||||
val kTypeParameterImpl = internalClass("KTypeParameterImpl")
|
||||
val kTypeImpl = internalClass("KTypeImpl")
|
||||
val kTypeImplForGenerics = internalClass("KTypeImplForGenerics")
|
||||
val kTypeImplForTypeParametersWithRecursiveBounds = internalClass("KTypeImplForTypeParametersWithRecursiveBounds")
|
||||
|
||||
val kTypeProjection = symbolTable.referenceClass(context.reflectionTypes.kTypeProjection)
|
||||
|
||||
|
||||
+2
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.ir.util.isSuspend
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.library.uniqueName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
|
||||
// This file describes the ABI for Kotlin descriptors of exported declarations.
|
||||
@@ -112,6 +113,7 @@ internal val IrClass.kotlinObjCClassInfoSymbolName: String
|
||||
}
|
||||
|
||||
val IrFunction.functionName get() = with(KonanBinaryInterface) { functionName }
|
||||
val IrFunction.fullName get() = parent.fqNameForIrSerialization.child(Name.identifier(functionName)).asString()
|
||||
|
||||
val IrFunction.symbolName get() = with(KonanBinaryInterface) { symbolName }
|
||||
|
||||
|
||||
+10
-5
@@ -33,8 +33,6 @@ import org.jetbrains.kotlin.name.Name
|
||||
internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass {
|
||||
private var tempIndex = 0
|
||||
|
||||
private val kTypeGenerator = KTypeGenerator(context)
|
||||
|
||||
private fun getKPropertyImplConstructor(receiverTypes: List<IrType>,
|
||||
returnType: IrType,
|
||||
isLocal: Boolean,
|
||||
@@ -109,19 +107,20 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
||||
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
|
||||
val kTypeGenerator = KTypeGenerator(context, irFile, expression)
|
||||
val startOffset = expression.startOffset
|
||||
val endOffset = expression.endOffset
|
||||
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, startOffset, endOffset)
|
||||
irBuilder.run {
|
||||
val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null }
|
||||
return when (receiversCount) {
|
||||
1 -> createKProperty(expression, this) // Has receiver.
|
||||
1 -> createKProperty(expression, kTypeGenerator, this) // Has receiver.
|
||||
|
||||
2 -> error("Callable reference to properties with two receivers is not allowed: ${expression.symbol.owner.name}")
|
||||
|
||||
else -> { // Cache KProperties with no arguments.
|
||||
val field = kProperties.getOrPut(expression.symbol.owner) {
|
||||
createKProperty(expression, this) to kProperties.size
|
||||
createKProperty(expression, kTypeGenerator, this) to kProperties.size
|
||||
}
|
||||
|
||||
irCall(arrayItemGetter).apply {
|
||||
@@ -149,6 +148,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
||||
createLocalKProperty(
|
||||
expression.symbol.owner.name.asString(),
|
||||
expression.getter.owner.returnType,
|
||||
KTypeGenerator(this@PropertyDelegationLowering.context, irFile, expression),
|
||||
this
|
||||
) to kProperties.size
|
||||
}
|
||||
@@ -172,7 +172,11 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
||||
}
|
||||
}
|
||||
|
||||
private fun createKProperty(expression: IrPropertyReference, irBuilder: IrBuilderWithScope): IrExpression {
|
||||
private fun createKProperty(
|
||||
expression: IrPropertyReference,
|
||||
kTypeGenerator: KTypeGenerator,
|
||||
irBuilder: IrBuilderWithScope
|
||||
): IrExpression {
|
||||
val startOffset = expression.startOffset
|
||||
val endOffset = expression.endOffset
|
||||
return irBuilder.irBlock(expression) {
|
||||
@@ -263,6 +267,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
|
||||
|
||||
private fun createLocalKProperty(propertyName: String,
|
||||
propertyType: IrType,
|
||||
kTypeGenerator: KTypeGenerator,
|
||||
irBuilder: IrBuilderWithScope): IrExpression {
|
||||
irBuilder.run {
|
||||
val (symbol, constructorTypeArguments) = getKPropertyImplConstructor(
|
||||
|
||||
+9
-11
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.backend.common.pop
|
||||
import org.jetbrains.kotlin.backend.common.push
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.functionName
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.fullName
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
|
||||
@@ -49,8 +49,6 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
|
||||
declaration.origin == DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL
|
||||
}
|
||||
|
||||
private val kTypeGenerator = KTypeGenerator(context)
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
var generatedClasses = mutableListOf<IrClass>()
|
||||
irFile.transform(object: IrElementTransformerVoidWithContext() {
|
||||
@@ -151,7 +149,7 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
|
||||
|
||||
fun transformFunctionReference(expression: IrFunctionReference, samSuperType: IrType? = null): IrExpression {
|
||||
val parent: IrDeclarationContainer = (currentClass?.irElement as? IrClass) ?: irFile
|
||||
val loweredFunctionReference = FunctionReferenceBuilder(parent, expression, samSuperType).build()
|
||||
val loweredFunctionReference = FunctionReferenceBuilder(irFile, parent, expression, samSuperType).build()
|
||||
generatedClasses.add(loweredFunctionReference.functionReferenceClass)
|
||||
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol,
|
||||
expression.startOffset, expression.endOffset)
|
||||
@@ -177,10 +175,12 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
|
||||
private val getContinuationSymbol = symbols.getContinuation
|
||||
private val continuationClassSymbol = getContinuationSymbol.owner.returnType.classifierOrFail as IrClassSymbol
|
||||
|
||||
private inner class FunctionReferenceBuilder(val parent: IrDeclarationParent,
|
||||
val functionReference: IrFunctionReference,
|
||||
val samSuperType: IrType?) {
|
||||
|
||||
private inner class FunctionReferenceBuilder(
|
||||
val irFile: IrFile,
|
||||
val parent: IrDeclarationParent,
|
||||
val functionReference: IrFunctionReference,
|
||||
val samSuperType: IrType?
|
||||
) {
|
||||
private val startOffset = functionReference.startOffset
|
||||
private val endOffset = functionReference.endOffset
|
||||
private val referencedFunction = functionReference.symbol.owner
|
||||
@@ -359,6 +359,7 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
|
||||
type = parameter.type.substitute(typeArgumentsMap))
|
||||
}
|
||||
|
||||
val kTypeGenerator = KTypeGenerator(context, irFile, functionReference)
|
||||
body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody {
|
||||
val superConstructor = when {
|
||||
isKSuspendFunction -> kSuspendFunctionImplConstructorSymbol.owner
|
||||
@@ -388,9 +389,6 @@ internal class FunctionReferenceLowering(val context: Context): FileLoweringPass
|
||||
}
|
||||
}
|
||||
|
||||
private val IrFunction.fullName: String
|
||||
get() = parent.fqNameForIrSerialization.child(Name.identifier(functionName)).asString()
|
||||
|
||||
private fun getFlags() =
|
||||
(if (referencedFunction.isSuspend) 1 else 0) + getAdaptedCallableReferenceFlags() shl 1
|
||||
|
||||
|
||||
+19
-37
@@ -6,18 +6,16 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer
|
||||
import org.jetbrains.kotlin.backend.common.lower.at
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.error
|
||||
import org.jetbrains.kotlin.backend.konan.renderCompilerError
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.util.irCall
|
||||
import org.jetbrains.kotlin.ir.util.isTypeOfIntrinsic
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
/**
|
||||
@@ -29,41 +27,31 @@ internal class PostInlineLowering(val context: Context) : FileLoweringPass {
|
||||
|
||||
private val symbols get() = context.ir.symbols
|
||||
|
||||
private val kTypeGenerator = KTypeGenerator(
|
||||
context,
|
||||
eraseTypeParameters = true // Mimic JVM BE behaviour until proper type parameter impl is ready.
|
||||
)
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||
irFile.transformChildrenVoid(object : IrBuildingTransformer(context) {
|
||||
|
||||
override fun visitClassReference(expression: IrClassReference): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
|
||||
val builder = createIrBuilder(expression)
|
||||
|
||||
val symbol = expression.symbol
|
||||
return if (symbol is IrClassSymbol) {
|
||||
builder.irKClass(context, symbol)
|
||||
} else {
|
||||
// E.g. for `T::class` in a body of an inline function itself.
|
||||
builder.irCall(context.ir.symbols.throwNullPointerException.owner)
|
||||
return builder.at(expression).run {
|
||||
(expression.symbol as? IrClassSymbol)?.let { irKClass(this@PostInlineLowering.context, it) }
|
||||
?:
|
||||
// E.g. for `T::class` in a body of an inline function itself.
|
||||
irCall(symbols.throwNullPointerException.owner)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitGetClass(expression: IrGetClass): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
|
||||
val builder = createIrBuilder(expression)
|
||||
return builder.at(expression).run {
|
||||
irCall(symbols.kClassImplConstructor, listOf(expression.argument.type)).apply {
|
||||
val typeInfo = irCall(symbols.getObjectTypeInfo).apply {
|
||||
putValueArgument(0, expression.argument)
|
||||
}
|
||||
|
||||
val typeArgument = expression.argument.type
|
||||
|
||||
return builder.irCall(symbols.kClassImplConstructor, listOf(typeArgument)).apply {
|
||||
val typeInfo = builder.irCall(symbols.getObjectTypeInfo).apply {
|
||||
putValueArgument(0, expression.argument)
|
||||
putValueArgument(0, typeInfo)
|
||||
}
|
||||
|
||||
putValueArgument(0, typeInfo)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,20 +82,14 @@ internal class PostInlineLowering(val context: Context) : FileLoweringPass {
|
||||
expression.startOffset, expression.endOffset,
|
||||
context.irBuiltIns.stringType,
|
||||
IrConstKind.String, builder.toString()))
|
||||
} else if (expression.symbol.owner.isTypeOfIntrinsic()) {
|
||||
val type = expression.getTypeArgument(0)
|
||||
?: error(irFile, expression, "missing type argument")
|
||||
return with (kTypeGenerator) { createIrBuilder(expression).irKType(type) }
|
||||
} else if (Symbols.isTypeOfIntrinsic(expression.symbol)) {
|
||||
return with (KTypeGenerator(context, irFile, expression, needExactTypeParameters = true)) {
|
||||
builder.at(expression).irKType(expression.getTypeArgument(0)!!, leaveReifiedForLater = false)
|
||||
}
|
||||
}
|
||||
|
||||
return expression
|
||||
}
|
||||
|
||||
private fun createIrBuilder(element: IrElement) = context.createIrBuilder(
|
||||
currentScope!!.scope.scopeOwnerSymbol,
|
||||
element.startOffset,
|
||||
element.endOffset
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
+30
-12
@@ -6,20 +6,27 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.IrBuildingTransformer
|
||||
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.KonanConfigKeys
|
||||
import org.jetbrains.kotlin.ir.builders.IrBuilderWithScope
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||
import org.jetbrains.kotlin.ir.types.isUnit
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.util.file
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
|
||||
/**
|
||||
* This pass runs before inlining and performs the following additional transformations over some operations:
|
||||
* - Assertion call removal.
|
||||
* - First phase of typeOf intrinsic lowering.
|
||||
*/
|
||||
internal class PreInlineLowering(val context: Context) : BodyLoweringPass {
|
||||
|
||||
@@ -29,19 +36,30 @@ internal class PreInlineLowering(val context: Context) : BodyLoweringPass {
|
||||
private val enableAssertions = context.config.configuration.getBoolean(KonanConfigKeys.ENABLE_ASSERTIONS)
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrBuildingTransformer(context) {
|
||||
irBody.transformChildren(object : IrElementTransformer<IrBuilderWithScope> {
|
||||
override fun visitDeclaration(declaration: IrDeclarationBase, data: IrBuilderWithScope) =
|
||||
super.visitDeclaration(declaration,
|
||||
data = (declaration as? IrSymbolOwner)?.let { context.createIrBuilder(it.symbol, it.startOffset, it.endOffset) }
|
||||
?: data
|
||||
)
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
override fun visitCall(expression: IrCall, data: IrBuilderWithScope): IrExpression {
|
||||
expression.transformChildren(this, data)
|
||||
|
||||
// Replace assert() call with an empty composite if assertions are not enabled.
|
||||
if (!enableAssertions && expression.symbol in asserts) {
|
||||
assert(expression.type.isUnit())
|
||||
return IrCompositeImpl(expression.startOffset, expression.endOffset, expression.type)
|
||||
return when {
|
||||
!enableAssertions && expression.symbol in asserts -> {
|
||||
// Replace assert() call with an empty composite if assertions are not enabled.
|
||||
require(expression.type.isUnit())
|
||||
IrCompositeImpl(expression.startOffset, expression.endOffset, expression.type)
|
||||
}
|
||||
Symbols.isTypeOfIntrinsic(expression.symbol) -> {
|
||||
with (KTypeGenerator(context, container.file, expression, needExactTypeParameters = true)) {
|
||||
data.at(expression).irKType(expression.getTypeArgument(0)!!, leaveReifiedForLater = true)
|
||||
}
|
||||
}
|
||||
else -> expression
|
||||
}
|
||||
|
||||
return expression
|
||||
}
|
||||
})
|
||||
}, data = context.createIrBuilder((container as IrSymbolOwner).symbol, irBody.startOffset, irBody.endOffset))
|
||||
}
|
||||
}
|
||||
+139
-49
@@ -10,94 +10,184 @@ 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.fullName
|
||||
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.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
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
|
||||
|
||||
internal class KTypeGenerator(
|
||||
private val context: KonanBackendContext,
|
||||
private val eraseTypeParameters: Boolean = false
|
||||
val context: KonanBackendContext,
|
||||
val irFile: IrFile,
|
||||
val irElement: IrElement,
|
||||
val needExactTypeParameters: Boolean = false
|
||||
) {
|
||||
private val symbols = context.ir.symbols
|
||||
|
||||
fun IrBuilderWithScope.irKType(type: IrType): IrExpression = if (type !is IrSimpleType) {
|
||||
// Represent as non-denotable type:
|
||||
irKTypeImpl(
|
||||
kClassifier = irNull(),
|
||||
irTypeArguments = emptyList(),
|
||||
isMarkedNullable = false
|
||||
)
|
||||
} else {
|
||||
val classifier = type.classifier
|
||||
fun IrBuilderWithScope.irKType(type: IrType, leaveReifiedForLater: Boolean = false) =
|
||||
irKType(type, leaveReifiedForLater, mutableSetOf())
|
||||
|
||||
if (classifier is IrClassSymbol) {
|
||||
irKTypeImpl(
|
||||
kClassifier = irKClass(classifier),
|
||||
irTypeArguments = type.arguments,
|
||||
isMarkedNullable = type.hasQuestionMark
|
||||
private class RecursiveBoundsException(message: String) : Throwable(message)
|
||||
|
||||
private fun IrBuilderWithScope.irKType(
|
||||
type: IrType,
|
||||
leaveReifiedForLater: Boolean,
|
||||
seenTypeParameters: MutableSet<IrTypeParameter>
|
||||
): IrExpression {
|
||||
if (type !is IrSimpleType) {
|
||||
// Represent as non-denotable type:
|
||||
return irKTypeImpl(
|
||||
kClassifier = irNull(),
|
||||
irTypeArguments = emptyList(),
|
||||
isMarkedNullable = false,
|
||||
leaveReifiedForLater = leaveReifiedForLater,
|
||||
seenTypeParameters = seenTypeParameters
|
||||
)
|
||||
} else {
|
||||
if (eraseTypeParameters) {
|
||||
irKType(context.irBuiltIns.anyNType)
|
||||
} else {
|
||||
irCall(symbols.kTypeImplForGenerics.constructors.single())
|
||||
}
|
||||
try {
|
||||
val kClassifier = when (val classifier = type.classifier) {
|
||||
is IrClassSymbol -> irKClass(classifier)
|
||||
is IrTypeParameterSymbol -> {
|
||||
if (classifier.owner.isReified && leaveReifiedForLater) {
|
||||
// Leave as is for reification.
|
||||
return irCall(symbols.typeOf).apply { putTypeArgument(0, type) }
|
||||
}
|
||||
|
||||
// Leave upper bounds of non-reified type parameters as is, even if they are reified themselves.
|
||||
irKTypeParameter(classifier.owner, leaveReifiedForLater = false, seenTypeParameters = seenTypeParameters)
|
||||
}
|
||||
else -> TODO("Unexpected classifier: $classifier")
|
||||
}
|
||||
|
||||
return irKTypeImpl(
|
||||
kClassifier = kClassifier,
|
||||
irTypeArguments = type.arguments,
|
||||
isMarkedNullable = type.hasQuestionMark,
|
||||
leaveReifiedForLater = leaveReifiedForLater,
|
||||
seenTypeParameters = seenTypeParameters
|
||||
)
|
||||
} catch (t: RecursiveBoundsException) {
|
||||
if (needExactTypeParameters)
|
||||
this@KTypeGenerator.context.reportCompilationError(t.message!!, irFile, irElement)
|
||||
return irCall(symbols.kTypeImplForTypeParametersWithRecursiveBounds.constructors.single())
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.irKTypeImpl(
|
||||
kClassifier: IrExpression,
|
||||
irTypeArguments: List<IrTypeArgument>,
|
||||
isMarkedNullable: Boolean
|
||||
isMarkedNullable: Boolean,
|
||||
leaveReifiedForLater: Boolean,
|
||||
seenTypeParameters: MutableSet<IrTypeParameter>
|
||||
): IrExpression = irCall(symbols.kTypeImpl.constructors.single()).apply {
|
||||
putValueArgument(0, kClassifier)
|
||||
putValueArgument(1, irKTypeProjectionsList(irTypeArguments))
|
||||
putValueArgument(1, irKTypeProjectionsList(irTypeArguments, leaveReifiedForLater, seenTypeParameters))
|
||||
putValueArgument(2, irBoolean(isMarkedNullable))
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.irKClass(symbol: IrClassSymbol) = irKClass(this@KTypeGenerator.context, symbol)
|
||||
|
||||
private fun IrBuilderWithScope.irKTypeProjectionsList(
|
||||
irTypeArguments: List<IrTypeArgument>
|
||||
private fun IrBuilderWithScope.irKTypeParameter(
|
||||
typeParameter: IrTypeParameter,
|
||||
leaveReifiedForLater: Boolean,
|
||||
seenTypeParameters: MutableSet<IrTypeParameter>
|
||||
): IrMemberAccessExpression<*> {
|
||||
val kTypeProjectionType = symbols.kTypeProjection.typeWithoutArguments
|
||||
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))
|
||||
}
|
||||
seenTypeParameters.remove(typeParameter)
|
||||
return result
|
||||
}
|
||||
|
||||
return if (irTypeArguments.isEmpty()) {
|
||||
irCall(symbols.emptyList, listOf(kTypeProjectionType))
|
||||
} else {
|
||||
irCall(symbols.listOf, listOf(kTypeProjectionType)).apply {
|
||||
putValueArgument(0, IrVarargImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
type = symbols.array.typeWith(kTypeProjectionType),
|
||||
varargElementType = kTypeProjectionType,
|
||||
elements = irTypeArguments.map { irKTypeProjection(it) }
|
||||
))
|
||||
}
|
||||
private val IrTypeParameter.parentUniqueName get() = when (val parent = parent) {
|
||||
is IrFunction -> parent.fullName
|
||||
else -> parent.fqNameForIrSerialization.asString()
|
||||
}
|
||||
|
||||
private val Variance.kVarianceName: String
|
||||
get() = when (this) {
|
||||
Variance.INVARIANT -> "INVARIANT"
|
||||
Variance.IN_VARIANCE -> "IN"
|
||||
Variance.OUT_VARIANCE -> "OUT"
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.irKVariance(variance: Variance) =
|
||||
IrGetEnumValueImpl(
|
||||
startOffset, endOffset,
|
||||
symbols.kVariance.defaultType,
|
||||
symbols.kVariance.owner.declarations
|
||||
.filterIsInstance<IrEnumEntry>()
|
||||
.single { it.name.asString() == variance.kVarianceName }.symbol
|
||||
)
|
||||
|
||||
private fun <T> IrBuilderWithScope.irKTypeLikeList(
|
||||
types: List<T>,
|
||||
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 fun IrBuilderWithScope.irKTypeProjection(argument: IrTypeArgument): IrExpression {
|
||||
return when (argument) {
|
||||
is IrTypeProjection -> irCall(symbols.kTypeProjectionFactories.getValue(argument.variance)).apply {
|
||||
dispatchReceiver = irGetObject(symbols.kTypeProjectionCompanion)
|
||||
putValueArgument(0, irKType(argument.type))
|
||||
}
|
||||
private fun IrBuilderWithScope.irKTypeList(
|
||||
types: List<IrType>,
|
||||
leaveReifiedForLater: Boolean,
|
||||
seenTypeParameters: MutableSet<IrTypeParameter>
|
||||
) = irKTypeLikeList(types, symbols.kType.defaultType) { irKType(it, leaveReifiedForLater, seenTypeParameters) }
|
||||
|
||||
is IrStarProjection -> irCall(symbols.kTypeProjectionStar.owner.getter!!).apply {
|
||||
dispatchReceiver = irGetObject(symbols.kTypeProjectionCompanion)
|
||||
}
|
||||
private fun IrBuilderWithScope.irKTypeProjectionsList(
|
||||
irTypeArguments: List<IrTypeArgument>,
|
||||
leaveReifiedForLater: Boolean,
|
||||
seenTypeParameters: MutableSet<IrTypeParameter>
|
||||
) = irKTypeLikeList(irTypeArguments, symbols.kTypeProjection.typeWithoutArguments) {
|
||||
irKTypeProjection(it, leaveReifiedForLater, seenTypeParameters)
|
||||
}
|
||||
|
||||
else -> error("Unexpected IrTypeArgument: $argument (${argument::class})")
|
||||
private fun IrBuilderWithScope.irKTypeProjection(
|
||||
argument: IrTypeArgument,
|
||||
leaveReifiedForLater: Boolean,
|
||||
seenTypeParameters: MutableSet<IrTypeParameter>
|
||||
) = 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})")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+36
-3
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.backend.konan.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.backend.common.ir.allParameters
|
||||
import org.jetbrains.kotlin.backend.common.lower.Closure
|
||||
import org.jetbrains.kotlin.backend.common.lower.ClosureAnnotator
|
||||
@@ -21,9 +22,11 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.isFinalClass
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
@@ -428,11 +431,11 @@ private class BackendChecker(val context: Context, val irFile: IrFile) : IrEleme
|
||||
getUnboundReferencedFunction(expression.getValueArgument(2)!!)
|
||||
?: reportError(expression, "${callee.fqNameForIrSerialization} must take an unbound, non-capturing function or lambda")
|
||||
}
|
||||
else -> when (callee.symbol) {
|
||||
symbols.createCleaner ->
|
||||
else -> when {
|
||||
callee.symbol == symbols.createCleaner ->
|
||||
getUnboundReferencedFunction(expression.getValueArgument(1)!!)
|
||||
?: reportError(expression, "${callee.fqNameForIrSerialization} must take an unbound, non-capturing function or lambda")
|
||||
symbols.immutableBlobOf -> {
|
||||
callee.symbol == symbols.immutableBlobOf -> {
|
||||
val args = expression.getValueArgument(0)
|
||||
?: reportError(expression, "expected at least one element")
|
||||
val elements = (args as IrVararg).elements
|
||||
@@ -446,6 +449,8 @@ private class BackendChecker(val context: Context, val irFile: IrFile) : IrEleme
|
||||
reportError(it, "incorrect value for binary data: $value")
|
||||
}
|
||||
}
|
||||
Symbols.isTypeOfIntrinsic(callee.symbol) ->
|
||||
checkIrKType(expression, expression.getTypeArgument(0)!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -486,6 +491,34 @@ private class BackendChecker(val context: Context, val irFile: IrFile) : IrEleme
|
||||
val typeParameter = symbol.owner.typeParameters.single()
|
||||
return getTypeArgument(typeParameter.index)!!
|
||||
}
|
||||
|
||||
private fun checkIrKType(
|
||||
irElement: IrElement,
|
||||
type: IrType,
|
||||
seenTypeParameters: MutableSet<IrTypeParameter> = mutableSetOf()
|
||||
) {
|
||||
if (type !is IrSimpleType)
|
||||
return
|
||||
val classifier = type.classifier
|
||||
if (classifier is IrTypeParameterSymbol)
|
||||
checkIrKTypeParameter(irElement, classifier.owner, seenTypeParameters)
|
||||
|
||||
type.arguments.forEach {
|
||||
if (it is IrTypeProjection)
|
||||
checkIrKType(irElement, it.type, seenTypeParameters)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkIrKTypeParameter(
|
||||
irElement: IrElement,
|
||||
typeParameter: IrTypeParameter,
|
||||
seenTypeParameters: MutableSet<IrTypeParameter>
|
||||
) {
|
||||
if (!seenTypeParameters.add(typeParameter))
|
||||
reportError(irElement, "Non-reified type parameters with recursive bounds are not supported yet: ${typeParameter.render()}")
|
||||
typeParameter.superTypes.forEach { checkIrKType(irElement, it, seenTypeParameters) }
|
||||
seenTypeParameters.remove(typeParameter)
|
||||
}
|
||||
}
|
||||
|
||||
private fun BackendChecker.checkCanGenerateCCall(expression: IrCall, isInvoke: Boolean) {
|
||||
|
||||
@@ -387,10 +387,5 @@ fun IrClass.defaultOrNullableType(hasQuestionMark: Boolean) =
|
||||
fun IrFunction.isRestrictedSuspendFunction(languageVersionSettings: LanguageVersionSettings): Boolean =
|
||||
this.descriptor.extensionReceiverParameter?.type?.isRestrictsSuspensionReceiver(languageVersionSettings) == true
|
||||
|
||||
fun IrFunction.isTypeOfIntrinsic(): Boolean =
|
||||
this.name.asString() == "typeOf" &&
|
||||
this.valueParameters.isEmpty() &&
|
||||
(this.parent as? IrPackageFragment)?.fqName == StandardNames.KOTLIN_REFLECT_FQ_NAME
|
||||
|
||||
fun IrBuilderWithScope.irByte(value: Byte) =
|
||||
IrConstImpl.byte(startOffset, endOffset, context.irBuiltIns.byteType, value)
|
||||
|
||||
@@ -1732,6 +1732,10 @@ task ktype1(type: KonanLocalTest) {
|
||||
source = "codegen/ktype/ktype1.kt"
|
||||
}
|
||||
|
||||
task ktype_nonReified(type: KonanLocalTest) {
|
||||
source = "codegen/ktype/nonReified.kt"
|
||||
}
|
||||
|
||||
task associatedObjects1(type: KonanLocalTest) {
|
||||
source = "codegen/associatedObjects/associatedObjects1.kt"
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ fun testBasics1() {
|
||||
assertEquals("$pkg.C<kotlin.Int?>", kType<C<Int?>>().toString())
|
||||
assertEquals("$pkg.C<$pkg.C<kotlin.Any>>", kType<C<C<Any>>>().toString())
|
||||
|
||||
assertEquals("$pkg.C<kotlin.Any?>", kTypeForCWithTypeParameter<D>().toString())
|
||||
assertEquals("$pkg.C<T>", kTypeForCWithTypeParameter<D>().toString())
|
||||
assertEquals("$pkg.Object", kType<Object>().toString())
|
||||
assertEquals("$pkg.Outer.Friend", kType<Outer.Friend>().toString())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package codegen.ktype.nonReified
|
||||
|
||||
import kotlin.test.*
|
||||
import kotlin.reflect.*
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
fun <T> foo() = typeOf<List<T>>()
|
||||
|
||||
@Test
|
||||
fun test_fun() {
|
||||
val l = foo<Int>()
|
||||
assertEquals(List::class, l.classifier)
|
||||
val t = l.arguments.single().type!!.classifier
|
||||
assertTrue(t is KTypeParameter)
|
||||
assertFalse((t as KTypeParameter).isReified)
|
||||
assertEquals("T", (t as KTypeParameter).name)
|
||||
}
|
||||
|
||||
class C<T> {
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
fun foo() = typeOf<List<T>>()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_class() {
|
||||
val l = C<Int>().foo()
|
||||
assertEquals(List::class, l.classifier)
|
||||
val t = l.arguments.single().type!!.classifier
|
||||
assertTrue(t is KTypeParameter)
|
||||
assertFalse((t as KTypeParameter).isReified)
|
||||
assertEquals("T", (t as KTypeParameter).name)
|
||||
}
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
fun <T> bar1() = typeOf<List<T>>()
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
fun <T> bar2() = typeOf<List<T>>()
|
||||
|
||||
class D {
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
fun <T> bar1() = typeOf<List<T>>()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_equality() {
|
||||
val t1 = bar1<Int>().arguments.single().type!!.classifier
|
||||
val t2 = bar2<Int>().arguments.single().type!!.classifier
|
||||
val t3 = D().bar1<Int>().arguments.single().type!!.classifier
|
||||
assertNotEquals(t1, t2)
|
||||
assertNotEquals(t1, t3)
|
||||
assertNotEquals(t2, t3)
|
||||
assertEquals(t1, bar1<Int>().arguments.single().type!!.classifier)
|
||||
assertEquals(t2, bar2<Int>().arguments.single().type!!.classifier)
|
||||
assertEquals(t3, D().bar1<Int>().arguments.single().type!!.classifier)
|
||||
}
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
inline fun <reified T, R : T> reifiedUpperBound() = typeOf<List<R>>()
|
||||
|
||||
@Test
|
||||
fun test_reifiedUpperBound() {
|
||||
val l = reifiedUpperBound<Any, Any>()
|
||||
assertEquals(List::class, l.classifier)
|
||||
val r = l.arguments.single().type!!.classifier
|
||||
assertTrue(r is KTypeParameter)
|
||||
assertFalse((r as KTypeParameter).isReified)
|
||||
assertEquals("R", (r as KTypeParameter).name)
|
||||
val t = (r as KTypeParameter).upperBounds.single().classifier
|
||||
assertTrue(t is KTypeParameter)
|
||||
assertTrue((t as KTypeParameter).isReified)
|
||||
assertEquals("T", (t as KTypeParameter).name)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import kotlin.reflect.*
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
fun <T : Comparable<T>> foo() {
|
||||
typeOf<List<T>>()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import kotlin.reflect.*
|
||||
|
||||
@OptIn(kotlin.ExperimentalStdlibApi::class)
|
||||
inline fun <reified T : Comparable<T>> foo() {
|
||||
typeOf<List<T>>()
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ internal class KTypeImpl(
|
||||
override fun toString(): String {
|
||||
val classifierString = when (classifier) {
|
||||
is KClass<*> -> classifier.qualifiedName ?: classifier.simpleName
|
||||
is KTypeParameter -> classifier.name
|
||||
else -> null
|
||||
} ?: return "(non-denotable type)"
|
||||
|
||||
@@ -37,16 +38,7 @@ internal class KTypeImpl(
|
||||
arguments.forEachIndexed { index, argument ->
|
||||
if (index > 0) append(", ")
|
||||
|
||||
if (argument.variance == null) {
|
||||
append('*')
|
||||
} else {
|
||||
append(when (argument.variance) {
|
||||
KVariance.INVARIANT -> ""
|
||||
KVariance.IN -> "in "
|
||||
KVariance.OUT -> "out "
|
||||
})
|
||||
append(argument.type)
|
||||
}
|
||||
append(argument)
|
||||
}
|
||||
|
||||
append('>')
|
||||
@@ -57,18 +49,18 @@ internal class KTypeImpl(
|
||||
}
|
||||
}
|
||||
|
||||
internal class KTypeImplForGenerics : KType {
|
||||
internal class KTypeImplForTypeParametersWithRecursiveBounds : KType {
|
||||
override val classifier: KClassifier?
|
||||
get() = error("Generic types are not yet supported in reflection")
|
||||
get() = error("Type parameters with recursive bounds are not yet supported in reflection")
|
||||
|
||||
override val arguments: List<KTypeProjection> get() = emptyList()
|
||||
|
||||
override val isMarkedNullable: Boolean
|
||||
get() = error("Generic types are not yet supported in reflection")
|
||||
get() = error("Type parameters with recursive bounds are not yet supported in reflection")
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
error("Generic types are not yet supported in reflection")
|
||||
error("Type parameters with recursive bounds are not yet supported in reflection")
|
||||
|
||||
override fun hashCode(): Int =
|
||||
error("Generic types are not yet supported in reflection")
|
||||
}
|
||||
error("Type parameters with recursive bounds are not yet supported in reflection")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
package kotlin.native.internal
|
||||
|
||||
import kotlin.reflect.*
|
||||
|
||||
internal class KTypeParameterImpl(
|
||||
override val name: String,
|
||||
private val containerFqName: String,
|
||||
override val upperBounds: List<KType>,
|
||||
override val variance: KVariance,
|
||||
override val isReified: Boolean
|
||||
) : KTypeParameter {
|
||||
override fun toString(): String = when (variance) {
|
||||
KVariance.INVARIANT -> ""
|
||||
KVariance.IN -> "in "
|
||||
KVariance.OUT -> "out "
|
||||
} + name
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is KTypeParameterImpl && name == other.name && containerFqName == other.containerFqName
|
||||
|
||||
override fun hashCode() = containerFqName.hashCode() * 31 + name.hashCode()
|
||||
}
|
||||
Reference in New Issue
Block a user