[IR] Supported non-reified typeOf

This commit is contained in:
Igor Chevdar
2020-09-20 20:41:04 +05:00
parent 1aef9da517
commit d67067a49e
18 changed files with 396 additions and 147 deletions
@@ -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",
@@ -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()
}
@@ -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)
@@ -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 }
@@ -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(
@@ -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
@@ -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
)
})
}
}
@@ -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))
}
}
@@ -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})")
}
}
@@ -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)
+4
View File
@@ -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"
}
+1 -1
View File
@@ -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()
}