Compiler symbolization part 3

This commit is contained in:
Igor Chevdar
2018-11-07 18:32:24 +03:00
parent e144321083
commit 99d32e0b8d
26 changed files with 1756 additions and 2488 deletions
@@ -6,16 +6,13 @@
package org.jetbrains.kotlin.backend.konan
import llvm.*
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
@@ -23,8 +20,9 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.name.Name
@@ -67,52 +65,41 @@ internal val Context.getBoxFunction: (IrClass) -> IrSimpleFunction by Context.la
val parameterType = unboxedType
val returnType = boxedType
val descriptor = SimpleFunctionDescriptorImpl.create(
inlinedClass.descriptor,
Annotations.EMPTY,
Name.special("<box>"),
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE
)
val parameter = ValueParameterDescriptorImpl(
descriptor,
null,
0,
Annotations.EMPTY,
Name.identifier("value"),
parameterType.toKotlinType(),
false,
false,
false,
null,
SourceElement.NO_SOURCE
)
descriptor.initialize(
null,
null,
emptyList(),
listOf(parameter),
returnType.toKotlinType(),
Modality.FINAL,
Visibilities.PUBLIC
)
val startOffset = inlinedClass.startOffset
val endOffset = inlinedClass.endOffset
IrFunctionImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, descriptor, returnType).apply {
this.valueParameters.add(IrValueParameterImpl(
startOffset,
endOffset,
IrDeclarationOrigin.DEFINED,
parameter,
parameterType,
null
))
this.parent = inlinedClass
val descriptor = WrappedSimpleFunctionDescriptor()
IrFunctionImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(descriptor),
Name.special("<box>"),
Visibilities.PUBLIC,
Modality.FINAL,
returnType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
).also { function ->
function.valueParameters.add(WrappedValueParameterDescriptor().let {
IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
IrValueParameterSymbolImpl(it),
Name.identifier("value"),
index = 0,
varargElementType = null,
isCrossinline = false,
type = parameterType,
isNoinline = false
).apply {
it.bind(this)
parent = function
}
})
descriptor.bind(function)
function.parent = inlinedClass
}
}
@@ -128,52 +115,41 @@ internal val Context.getUnboxFunction: (IrClass) -> IrSimpleFunction by Context.
val parameterType = boxedType
val returnType = unboxedType
val descriptor = SimpleFunctionDescriptorImpl.create(
inlinedClass.descriptor,
Annotations.EMPTY,
Name.special("<unbox>"),
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE
)
val parameter = ValueParameterDescriptorImpl(
descriptor,
null,
0,
Annotations.EMPTY,
Name.identifier("value"),
parameterType.toKotlinType(),
false,
false,
false,
null,
SourceElement.NO_SOURCE
)
descriptor.initialize(
null,
null,
emptyList(),
listOf(parameter),
returnType.toKotlinType(),
Modality.FINAL,
Visibilities.PUBLIC
)
val startOffset = inlinedClass.startOffset
val endOffset = inlinedClass.endOffset
IrFunctionImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, descriptor, returnType).apply {
this.valueParameters.add(IrValueParameterImpl(
startOffset,
endOffset,
IrDeclarationOrigin.DEFINED,
parameter,
parameterType,
null
))
this.parent = inlinedClass
val descriptor = WrappedSimpleFunctionDescriptor()
IrFunctionImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(descriptor),
Name.special("<unbox>"),
Visibilities.PUBLIC,
Modality.FINAL,
returnType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
).also { function ->
function.valueParameters.add(WrappedValueParameterDescriptor().let {
IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
IrValueParameterSymbolImpl(it),
Name.identifier("value"),
index = 0,
varargElementType = null,
isCrossinline = false,
type = parameterType,
isNoinline = false
).apply {
it.bind(this)
parent = function
}
})
descriptor.bind(function)
function.parent = inlinedClass
}
}
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.backend.konan
import llvm.LLVMDumpModule
import llvm.LLVMModuleRef
import org.jetbrains.kotlin.backend.common.DumpIrTreeWithDescriptorsVisitor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescriptor
import org.jetbrains.kotlin.backend.common.validateIrModule
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.KonanIr
@@ -20,8 +22,6 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.SourceManager
@@ -29,15 +29,13 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrTypeParameterImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.name.FqName
@@ -51,6 +49,8 @@ import org.jetbrains.kotlin.serialization.deserialization.getName
import java.lang.System.out
import kotlin.LazyThreadSafetyMode.PUBLICATION
import kotlin.reflect.KProperty
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
/**
* Offset for synthetic elements created by lowerings and not attributable to other places in the source code.
@@ -97,7 +97,7 @@ internal class SpecialDeclarationsFactory(val context: Context) {
}
fun getLoweredEnum(enumClass: IrClass): LoweredEnum {
assert(enumClass.kind == ClassKind.ENUM_CLASS, { "Expected enum class but was: ${enumClass.descriptor}" })
assert(enumClass.kind == ClassKind.ENUM_CLASS) { "Expected enum class but was: ${enumClass.descriptor}" }
return loweredEnums.getOrPut(enumClass) {
enumSpecialDeclarationsFactory.createLoweredEnum(enumClass)
}
@@ -125,143 +125,81 @@ internal class SpecialDeclarationsFactory(val context: Context) {
fun getBridge(overriddenFunctionDescriptor: OverriddenFunctionDescriptor): IrSimpleFunction {
val irFunction = overriddenFunctionDescriptor.descriptor
assert(overriddenFunctionDescriptor.needBridge,
{ "Function ${irFunction.descriptor} is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor.descriptor}" })
assert(overriddenFunctionDescriptor.needBridge) {
"Function ${irFunction.descriptor} is not needed in a bridge to call overridden function ${overriddenFunctionDescriptor.overriddenDescriptor.descriptor}"
}
val bridgeDirections = overriddenFunctionDescriptor.bridgeDirections
return bridgesDescriptors.getOrPut(irFunction to bridgeDirections) {
createBridge(irFunction, bridgeDirections)
}
}
private fun createBridge(function: IrFunction, bridgeDirections: BridgeDirections): IrFunctionImpl {
private fun createBridge(function: IrSimpleFunction,
bridgeDirections: BridgeDirections) = WrappedSimpleFunctionDescriptor().let { descriptor ->
val startOffset = function.startOffset
val endOffset = function.endOffset
val returnType = when (bridgeDirections.array[0]) {
BridgeDirection.TO_VALUE_TYPE,
BridgeDirection.NOT_NEEDED -> function.returnType
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType
}
val dispatchReceiver = when (bridgeDirections.array[1]) {
BridgeDirection.TO_VALUE_TYPE -> function.dispatchReceiverParameter!!
BridgeDirection.NOT_NEEDED -> function.dispatchReceiverParameter
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyClass.owner.thisReceiver!!
}
val extensionReceiverType = when (bridgeDirections.array[2]) {
BridgeDirection.TO_VALUE_TYPE -> function.extensionReceiverParameter!!.type
BridgeDirection.NOT_NEEDED -> function.extensionReceiverParameter?.type
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType
}
val valueParameterTypes = function.valueParameters.mapIndexed { index, valueParameter ->
when (bridgeDirections.array[index + 3]) {
BridgeDirection.TO_VALUE_TYPE -> valueParameter.type
BridgeDirection.NOT_NEEDED -> valueParameter.type
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType
}
}
val bridgeDescriptor = createBridgeDescriptor(
function,
bridgeDirections,
returnType,
dispatchReceiver,
extensionReceiverType,
valueParameterTypes
)
val bridge = IrFunctionImpl(
function.startOffset,
function.endOffset,
IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_BRIDGE_METHOD(function),
bridgeDescriptor,
returnType
IrSimpleFunctionSymbolImpl(descriptor),
"<bridge-$bridgeDirections>${function.functionName}".synthesizedName,
function.visibility,
function.modality,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = function.isSuspend,
returnType = returnType
).apply {
this.parent = function.parent
}
descriptor.bind(this)
parent = function.parent
bridge.dispatchReceiverParameter = dispatchReceiver?.let {
IrValueParameterImpl(
it.startOffset,
it.endOffset,
IrDeclarationOrigin.DEFINED,
it.descriptor,
it.type,
null
)
}
val dispatchReceiver = when (bridgeDirections.array[1]) {
BridgeDirection.TO_VALUE_TYPE -> function.dispatchReceiverParameter!!
BridgeDirection.NOT_NEEDED -> function.dispatchReceiverParameter
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyClass.owner.thisReceiver!!
}
extensionReceiverType?.let {
val extensionReceiverParameter = function.extensionReceiverParameter!!
bridge.extensionReceiverParameter = IrValueParameterImpl(
extensionReceiverParameter.startOffset,
extensionReceiverParameter.endOffset,
extensionReceiverParameter.origin,
bridge.descriptor.extensionReceiverParameter!!,
it, null
)
}
function.valueParameters.mapIndexedTo(bridge.valueParameters) { index, valueParameter ->
val type = valueParameterTypes[index]
val extensionReceiver = when (bridgeDirections.array[2]) {
BridgeDirection.TO_VALUE_TYPE -> function.extensionReceiverParameter!!
BridgeDirection.NOT_NEEDED -> function.extensionReceiverParameter
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyClass.owner.thisReceiver!!
}
IrValueParameterImpl(
valueParameter.startOffset,
valueParameter.endOffset,
valueParameter.origin,
bridge.descriptor.valueParameters[index],
type, valueParameter.varargElementType
)
}
val valueParameterTypes = function.valueParameters.mapIndexed { index, valueParameter ->
when (bridgeDirections.array[index + 3]) {
BridgeDirection.TO_VALUE_TYPE -> valueParameter.type
BridgeDirection.NOT_NEEDED -> valueParameter.type
BridgeDirection.FROM_VALUE_TYPE -> context.irBuiltIns.anyNType
}
}
function.typeParameters.mapTo(bridge.typeParameters) {
IrTypeParameterImpl(it.startOffset, it.endOffset, it.origin, it.descriptor).apply {
superTypes += it.superTypes
dispatchReceiverParameter = dispatchReceiver?.copyTo(this)
extensionReceiverParameter = extensionReceiver?.copyTo(this)
function.valueParameters.mapTo(valueParameters) { it.copyTo(this, type = valueParameterTypes[it.index]) }
function.typeParameters.mapIndexedTo(typeParameters) { index, parameter ->
WrappedTypeParameterDescriptor().let {
IrTypeParameterImpl(
startOffset, endOffset,
origin,
IrTypeParameterSymbolImpl(it),
parameter.name,
index,
parameter.isReified,
parameter.variance
).apply {
it.bind(this)
superTypes += parameter.superTypes
}
}
}
}
return bridge
}
private fun createBridgeDescriptor(
function: IrFunction,
bridgeDirections: BridgeDirections,
returnType: IrType,
dispatchReceiverParameter: IrValueParameter?,
extensionReceiverType: IrType?,
valueParameterTypes: List<IrType>
): SimpleFunctionDescriptor {
val descriptor = function.descriptor
val bridgeDescriptor = SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ descriptor.containingDeclaration,
/* annotations = */ Annotations.EMPTY,
/* name = */ "<bridge-$bridgeDirections>${function.functionName}".synthesizedName,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE)
val valueParameters = descriptor.valueParameters.mapIndexed { index, valueParameterDescriptor ->
ValueParameterDescriptorImpl(
containingDeclaration = valueParameterDescriptor.containingDeclaration,
original = null,
index = index,
annotations = Annotations.EMPTY,
name = valueParameterDescriptor.name,
outType = valueParameterTypes[index].toKotlinType(),
declaresDefaultValue = valueParameterDescriptor.declaresDefaultValue(),
isCrossinline = valueParameterDescriptor.isCrossinline,
isNoinline = valueParameterDescriptor.isNoinline,
varargElementType = valueParameterDescriptor.varargElementType,
source = SourceElement.NO_SOURCE)
}
bridgeDescriptor.initialize(
/* receiverParameterType = */ extensionReceiverType?.toKotlinType(),
/* dispatchReceiverParameter = */ dispatchReceiverParameter?.descriptor as ReceiverParameterDescriptor?,
/* typeParameters = */ descriptor.typeParameters,
/* unsubstitutedValueParameters = */ valueParameters,
/* unsubstitutedReturnType = */ returnType.toKotlinType(),
/* modality = */ descriptor.modality,
/* visibility = */ descriptor.visibility).apply {
isSuspend = descriptor.isSuspend
}
return bridgeDescriptor
}
}
@@ -5,143 +5,123 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedFieldDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.descriptors.enumEntries
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.*
internal object DECLARATION_ORIGIN_ENUM :
IrDeclarationOriginImpl("ENUM")
internal object DECLARATION_ORIGIN_ENUM : IrDeclarationOriginImpl("ENUM")
internal data class LoweredEnum(val implObject: IrClass,
val valuesField: IrField,
val valuesGetter: IrSimpleFunction,
val itemGetterSymbol: IrSimpleFunctionSymbol,
val itemGetterDescriptor: FunctionDescriptor,
val entriesMap: Map<Name, Int>)
internal class EnumSpecialDeclarationsFactory(val context: Context) {
fun createLoweredEnum(enumClass: IrClass): LoweredEnum {
val enumClassDescriptor = enumClass.descriptor
private val symbols = context.ir.symbols
fun createLoweredEnum(enumClass: IrClass): LoweredEnum {
val startOffset = enumClass.startOffset
val endOffset = enumClass.endOffset
val implObjectDescriptor = ClassDescriptorImpl(enumClassDescriptor, "OBJECT".synthesizedName, Modality.FINAL,
ClassKind.OBJECT, listOf(context.builtIns.anyType), SourceElement.NO_SOURCE, false, LockBasedStorageManager.NO_LOCKS)
val implObject = IrClassImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, implObjectDescriptor).apply {
createParameterDeclarations()
val implObject = WrappedClassDescriptor().let {
IrClassImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrClassSymbolImpl(it),
"OBJECT".synthesizedName,
ClassKind.OBJECT,
Visibilities.PUBLIC,
Modality.FINAL,
isCompanion = false,
isInner = false,
isData = false,
isExternal = false,
isInline = false
).apply {
it.bind(this)
parent = enumClass
createParameterDeclarations()
}
}
val valuesProperty = createEnumValuesField(enumClassDescriptor, implObjectDescriptor)
val valuesType = context.ir.symbols.array.typeWith(enumClass.defaultType)
val valuesField = IrFieldImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, valuesProperty, valuesType)
val valuesGetterDescriptor = createValuesGetterDescriptor(enumClassDescriptor, implObjectDescriptor)
val valuesGetter = IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
valuesGetterDescriptor,
valuesType
).also {
it.parent = implObject
it.createDispatchReceiverParameter()
val valuesType = symbols.array.typeWith(enumClass.defaultType)
val valuesField = WrappedFieldDescriptor().let {
IrFieldImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrFieldSymbolImpl(it),
"VALUES".synthesizedName,
valuesType,
Visibilities.PRIVATE,
isFinal = true,
isExternal = false,
isStatic = false
).apply {
it.bind(this)
parent = implObject
}
}
val memberScope = MemberScope.Empty
val valuesGetter = WrappedSimpleFunctionDescriptor().let {
IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrSimpleFunctionSymbolImpl(it),
"get-VALUES".synthesizedName,
Visibilities.PUBLIC,
Modality.FINAL,
valuesType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
).apply {
it.bind(this)
parent = implObject
}
}
val constructorOfAny = context.irBuiltIns.anyClass.owner.constructors.first()
// TODO: why primary?
val constructor = implObject.addSimpleDelegatingConstructor(
implObject.addSimpleDelegatingConstructor(
constructorOfAny,
context.irBuiltIns,
DECLARATION_ORIGIN_ENUM,
true
true // TODO: why primary?
)
val constructorDescriptor = constructor.descriptor
implObjectDescriptor.initialize(memberScope, setOf(constructorDescriptor), constructorDescriptor)
implObject.setSuperSymbolsAndAddFakeOverrides(listOf(context.irBuiltIns.anyType))
implObject.parent = enumClass
valuesField.parent = implObject
implObject.superTypes += context.irBuiltIns.anyType
implObject.addFakeOverrides()
val (itemGetterSymbol, itemGetterDescriptor) = getEnumItemGetter(enumClassDescriptor)
val itemGetterSymbol = symbols.array.functions.single { it.descriptor.name == Name.identifier("get") }
val enumEntriesMap = enumClass.declarations
.filterIsInstance<IrEnumEntry>()
.sortedBy { it.name }
.withIndex()
.associate { it.value.name to it.index }
.toMap()
return LoweredEnum(
implObject,
valuesField,
valuesGetter,
itemGetterSymbol, itemGetterDescriptor,
createEnumEntriesMap(enumClassDescriptor))
itemGetterSymbol,
enumEntriesMap)
}
private fun createValuesGetterDescriptor(enumClassDescriptor: ClassDescriptor, implObjectDescriptor: ClassDescriptor)
: FunctionDescriptor {
val returnType = genericArrayType.defaultType.replace(listOf(TypeProjectionImpl(enumClassDescriptor.defaultType)))
val result = SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ implObjectDescriptor,
/* annotations = */ Annotations.EMPTY,
/* name = */ "get-VALUES".synthesizedName,
/* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED,
/* source = */ SourceElement.NO_SOURCE)
result.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ null,
/* typeParameters = */ listOf(),
/* unsubstitutedValueParameters = */ listOf(),
/* unsubstitutedReturnType = */ returnType,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PUBLIC)
return result
}
private fun createEnumValuesField(enumClassDescriptor: ClassDescriptor, implObjectDescriptor: ClassDescriptor): PropertyDescriptor {
val valuesArrayType = context.builtIns.getArrayType(Variance.INVARIANT, enumClassDescriptor.defaultType)
val receiver = ReceiverParameterDescriptorImpl(
implObjectDescriptor,
ImplicitClassReceiver(implObjectDescriptor, null),
Annotations.EMPTY
)
return PropertyDescriptorImpl.create(implObjectDescriptor, Annotations.EMPTY, Modality.FINAL, Visibilities.PUBLIC,
false, "VALUES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE,
false, false, false, false, false, false).apply {
this.setType(valuesArrayType, emptyList(), receiver, null)
this.initialize(null, null)
}
}
private val genericArrayType = context.ir.symbols.array.descriptor
private fun getEnumItemGetter(enumClassDescriptor: ClassDescriptor): Pair<IrSimpleFunctionSymbol, FunctionDescriptor> {
val getter = context.ir.symbols.array.functions.single { it.descriptor.name == Name.identifier("get") }
val typeParameterT = genericArrayType.declaredTypeParameters[0]
val enumClassType = enumClassDescriptor.defaultType
val typeSubstitutor = TypeSubstitutor.create(mapOf(typeParameterT.typeConstructor to TypeProjectionImpl(enumClassType)))
return getter to getter.descriptor.substitute(typeSubstitutor)!!
}
private fun createEnumEntriesMap(enumClassDescriptor: ClassDescriptor): Map<Name, Int> {
val map = mutableMapOf<Name, Int>()
enumClassDescriptor.enumEntries
.sortedBy { it.name }
.forEachIndexed { index, entry -> map.put(entry.name, index) }
return map
}
}
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.backend.konan.lower.ExpectDeclarationsRemoving
import org.jetbrains.kotlin.backend.konan.lower.FinallyBlocksLowering
import org.jetbrains.kotlin.backend.konan.lower.InitializersLowering
import org.jetbrains.kotlin.backend.konan.lower.LateinitLowering
import org.jetbrains.kotlin.backend.konan.lower.SharedVariablesLowering
import org.jetbrains.kotlin.backend.konan.lower.VarargInjectionLowering
import org.jetbrains.kotlin.backend.konan.lower.loops.ForLoopsLowering
import org.jetbrains.kotlin.ir.declarations.IrFile
@@ -65,10 +64,6 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager)
irModule.files.forEach(InteropLoweringPart1(context)::lower)
}
phaser.phase(KonanPhase.LOWER_LATEINIT) {
irModule.files.forEach(LateinitLowering(context)::lower)
}
val symbolTable = context.ir.symbols.symbolTable
do {
@@ -82,6 +77,9 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager)
}
private fun lowerFile(irFile: IrFile, phaser: PhaseManager) {
phaser.phase(KonanPhase.LOWER_LATEINIT) {
LateinitLowering(context).lower(irFile)
}
phaser.phase(KonanPhase.LOWER_STRING_CONCAT) {
StringConcatenationLowering(context).lower(irFile)
}
@@ -94,13 +92,6 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager)
phaser.phase(KonanPhase.LOWER_ENUMS) {
EnumClassLowering(context).run(irFile)
}
/**
* TODO: this is workaround for issue of unitialized parents in IrDeclaration,
* the last one detected in [EnumClassLowering]. The issue appears in [DefaultArgumentStubGenerator].
*/
irFile.patchDeclarationParents()
phaser.phase(KonanPhase.LOWER_INITIALIZERS) {
InitializersLowering(context).runOnFilePostfix(irFile)
}
@@ -113,12 +104,6 @@ internal class KonanLower(val context: Context, val parentPhaser: PhaseManager)
phaser.phase(KonanPhase.LOWER_CALLABLES) {
CallableReferenceLowering(context).lower(irFile)
}
/**
* TODO: this is workaround for issue of unitialized parents in IrDeclaration,
* the last one detected in [CallableReferenceLowering]. The issue appears in [LocalDeclarationsLowering].
*/
irFile.patchDeclarationParents()
phaser.phase(KonanPhase.LOWER_LOCAL_FUNCTIONS) {
LocalDeclarationsLowering(context).runOnFilePostfix(irFile)
}
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.backend.konan.llvm.findMainEntryPoint
import org.jetbrains.kotlin.backend.konan.lower.TestProcessor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.config.coroutinesIntrinsicsPackageFqName
import org.jetbrains.kotlin.config.coroutinesPackageFqName
import org.jetbrains.kotlin.config.languageVersionSettings
@@ -370,6 +369,9 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
val getContinuation = symbolTable.referenceSimpleFunction(
context.getInternalFunctions("getContinuation").single())
val returnIfSuspended = symbolTable.referenceSimpleFunction(
context.getInternalFunctions("returnIfSuspended").single())
val konanSuspendCoroutineUninterceptedOrReturn = symbolTable.referenceSimpleFunction(
context.getInternalFunctions("suspendCoroutineUninterceptedOrReturn").single())
@@ -435,10 +437,14 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
} && !it.isExpect
}
val isInitializedGetterDescriptor = isInitializedPropertyDescriptor.getter!!
val isInitializedGetter = symbolTable.referenceSimpleFunction(isInitializedPropertyDescriptor.getter!!)
val kFunctionImpl = symbolTable.referenceClass(context.reflectionTypes.kFunctionImpl)
val kMutableProperty0 = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty0)
val kMutableProperty1 = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty1)
val kMutableProperty2 = symbolTable.referenceClass(context.reflectionTypes.kMutableProperty2)
val kProperty0Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty0Impl)
val kProperty1Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty1Impl)
val kProperty2Impl = symbolTable.referenceClass(context.reflectionTypes.kProperty2Impl)
@@ -502,32 +508,6 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable, val
val topLevelSuite = getKonanTestClass("TopLevelSuite")
val testFunctionKind = getKonanTestClass("TestFunctionKind")
val baseClassSuiteConstructor = baseClassSuite.descriptor.constructors.single {
it.valueParameters.size == 2 &&
KotlinBuiltIns.isString(it.valueParameters[0].type) && // name: String
KotlinBuiltIns.isBoolean(it.valueParameters[1].type) // ignored: Boolean
}
val topLevelSuiteConstructor = symbolTable.referenceConstructor(topLevelSuite.descriptor.constructors.single {
it.valueParameters.size == 1 &&
KotlinBuiltIns.isString(it.valueParameters[0].type) // name: String
})
val topLevelSuiteRegisterFunction =
getFunction(Name.identifier("registerFunction"), topLevelSuite.descriptor.defaultType) {
it.valueParameters.size == 2 &&
it.valueParameters[0].type == testFunctionKind.descriptor.defaultType && // kind: TestFunctionKind
it.valueParameters[1].type.isFunctionType // function: () -> Unit
}
val topLevelSuiteRegisterTestCase =
getFunction(Name.identifier("registerTestCase"), topLevelSuite.descriptor.defaultType) {
it.valueParameters.size == 3 &&
KotlinBuiltIns.isString(it.valueParameters[0].type) && // name: String
it.valueParameters[1].type.isFunctionType && // function: () -> Unit
KotlinBuiltIns.isBoolean(it.valueParameters[2].type) // ignored: Boolean
}
private val testFunctionKindCache = mutableMapOf<TestProcessor.FunctionKind, IrEnumEntrySymbol>()
fun getTestFunctionKind(kind: TestProcessor.FunctionKind): IrEnumEntrySymbol = testFunctionKindCache.getOrPut(kind) {
symbolTable.referenceEnumEntry(testFunctionKind.descriptor.unsubstitutedMemberScope.getContributedClassifier(
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.AbstractValueUsageTransformer
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.atMostOne
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.target
@@ -15,9 +17,7 @@ import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass
import org.jetbrains.kotlin.backend.konan.irasdescriptors.containsNull
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isOverridable
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isSuspend
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -67,17 +68,17 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
}
}
private var currentFunctionDescriptor: IrFunction? = null
private var currentFunction: IrFunction? = null
override fun visitFunction(declaration: IrFunction): IrStatement {
currentFunctionDescriptor = declaration
currentFunction = declaration
val result = super.visitFunction(declaration)
currentFunctionDescriptor = null
currentFunction = null
return result
}
override fun IrExpression.useAsReturnValue(returnTarget: IrReturnTargetSymbol): IrExpression = when (returnTarget) {
is IrSimpleFunctionSymbol -> if (returnTarget.owner.isSuspend && returnTarget == currentFunctionDescriptor?.symbol) {
is IrSimpleFunctionSymbol -> if (returnTarget.owner.isSuspend && returnTarget == currentFunction?.symbol) {
this.useAs(irBuiltIns.anyNType)
} else {
this.useAs(returnTarget.owner.returnType)
@@ -389,6 +390,7 @@ private class InlineClassTransformer(private val context: Context) : IrBuildingT
}
(irConstructor.body as IrBlockBody).statements.forEach { statement ->
statement.setDeclarationsParent(result)
+statement.transform(object : IrElementTransformerVoid() {
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.transformChildrenVoid()
@@ -435,38 +437,22 @@ private val Context.getLoweredInlineClassConstructor: (IrConstructor) -> IrSimpl
require(irConstructor.constructedClass.isInlined())
require(!irConstructor.isPrimary)
val descriptor = SimpleFunctionDescriptorImpl.create(
irConstructor.descriptor.containingDeclaration,
irConstructor.descriptor.annotations,
Name.special("<constructor>"),
CallableMemberDescriptor.Kind.SYNTHESIZED,
irConstructor.descriptor.source
)
val parameterDescriptors = irConstructor.descriptor.valueParameters.map {
it.copy(descriptor, it.name, it.index)
}
descriptor.initialize(
null,
null,
emptyList(),
parameterDescriptors,
irConstructor.descriptor.returnType,
Modality.FINAL,
irConstructor.visibility
)
val descriptor = WrappedSimpleFunctionDescriptor(irConstructor.descriptor.annotations, irConstructor.descriptor.source)
IrFunctionImpl(
irConstructor.startOffset,
irConstructor.endOffset,
irConstructor.startOffset, irConstructor.endOffset,
IrDeclarationOrigin.DEFINED,
descriptor,
irConstructor.returnType
IrSimpleFunctionSymbolImpl(descriptor),
Name.special("<constructor>"),
irConstructor.visibility,
Modality.FINAL,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false,
returnType = irConstructor.returnType
).apply {
descriptor.bind(this)
parent = irConstructor.parent
irConstructor.valueParameters.mapTo(this.valueParameters) {
it.copy(this.descriptor.valueParameters[it.index])
}
irConstructor.valueParameters.mapTo(valueParameters) { it.copyTo(this) }
}
}
@@ -7,15 +7,14 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.backend.common.lower.irIfThen
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
@@ -26,6 +25,8 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isNullableAny
import org.jetbrains.kotlin.ir.util.simpleFunctions
@@ -64,54 +65,41 @@ internal class WorkersBridgesBuilding(val context: Context) : DeclarationContain
val job = expression.getValueArgument(3) as IrFunctionReference
val jobFunction = (job.symbol as IrSimpleFunctionSymbol).owner
val jobDescriptor = job.descriptor
val arg = jobDescriptor.valueParameters[0]
if (!::runtimeJobFunction.isInitialized) {
val runtimeJobDescriptor = SimpleFunctionDescriptorImpl.create(
jobDescriptor.containingDeclaration,
jobDescriptor.annotations,
jobDescriptor.name,
jobDescriptor.kind,
jobDescriptor.source
val arg = jobFunction.valueParameters[0]
val startOffset = jobFunction.startOffset
val endOffset = jobFunction.endOffset
runtimeJobFunction = WrappedSimpleFunctionDescriptor().let {
IrFunctionImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
IrSimpleFunctionSymbolImpl(it),
jobFunction.name,
jobFunction.visibility,
jobFunction.modality,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false,
returnType = context.irBuiltIns.anyNType
).apply {
initialize(
null,
null,
emptyList(),
listOf(ValueParameterDescriptorImpl(
containingDeclaration = this,
original = null,
index = 0,
annotations = Annotations.EMPTY,
name = arg.name,
outType = nullableAnyType,
declaresDefaultValue = arg.declaresDefaultValue(),
isCrossinline = arg.isCrossinline,
isNoinline = arg.isNoinline,
varargElementType = arg.varargElementType,
source = arg.source
)),
nullableAnyType,
jobDescriptor.modality,
jobDescriptor.visibility
)
it.bind(this)
}
}
runtimeJobFunction = IrFunctionImpl(
jobFunction.startOffset,
jobFunction.endOffset,
IrDeclarationOrigin.DEFINED,
runtimeJobDescriptor,
context.irBuiltIns.anyNType
).also {
it.valueParameters += IrValueParameterImpl(
it.startOffset,
it.endOffset,
runtimeJobFunction.valueParameters += WrappedValueParameterDescriptor().let {
IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.DEFINED,
it.descriptor.valueParameters.single(),
context.irBuiltIns.anyNType,
null
)
IrValueParameterSymbolImpl(it),
arg.name,
arg.index,
type = context.irBuiltIns.anyNType,
varargElementType = null,
isCrossinline = arg.isCrossinline,
isNoinline = arg.isNoinline
).apply { it.bind(this) }
}
}
val overriddenJobDescriptor = OverriddenFunctionDescriptor(jobFunction, runtimeJobFunction)
@@ -7,6 +7,8 @@ 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.descriptors.*
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
@@ -15,14 +17,7 @@ import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isFunctionOrKFunctionType
import org.jetbrains.kotlin.backend.konan.llvm.functionName
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
@@ -32,9 +27,8 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.*
@@ -42,8 +36,6 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager
internal class CallableReferenceLowering(val context: Context): FileLoweringPass {
@@ -108,12 +100,9 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
}
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().last()
val loweredFunctionReference = FunctionReferenceBuilder(
currentScope!!.scope.scopeOwner,
parent,
expression
).build()
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset)
val loweredFunctionReference = FunctionReferenceBuilder(parent, expression).build()
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol,
expression.startOffset, expression.endOffset)
return irBuilder.irBlock(expression) {
+loweredFunctionReference.functionReferenceClass
+irCall(loweredFunctionReference.functionReferenceConstructor.symbol).apply {
@@ -138,34 +127,64 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
private val getContinuationSymbol = symbols.getContinuation
private inner class FunctionReferenceBuilder(val containingDeclaration: DeclarationDescriptor,
val parent: IrDeclarationParent,
private inner class FunctionReferenceBuilder(val parent: IrDeclarationParent,
val functionReference: IrFunctionReference) {
private val functionDescriptor = functionReference.descriptor.original
private val irFunction = functionReference.symbol.owner
private val functionParameters = irFunction.explicitParameters
private val startOffset = functionReference.startOffset
private val endOffset = functionReference.endOffset
private val referencedFunction = functionReference.symbol.owner
private val functionParameters = referencedFunction.explicitParameters
private val boundFunctionParameters = functionReference.getArgumentsWithIr().map { it.first }
private val unboundFunctionParameters = functionParameters - boundFunctionParameters
private lateinit var functionReferenceClassDescriptor: ClassDescriptorImpl
private lateinit var functionReferenceClass: IrClassImpl
private lateinit var functionReferenceThis: IrValueParameterSymbol
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, IrField>
private val typeArgumentsMap = referencedFunction.typeParameters.associate { typeParam ->
typeParam.symbol to functionReference.getTypeArgument(typeParam.index)!!
}
private val functionReferenceClass = WrappedClassDescriptor().let {
IrClassImpl(
startOffset,endOffset,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
IrClassSymbolImpl(it),
"${referencedFunction.name}\$FUNCTION_REFERENCE\$${context.functionReferenceCount++}".synthesizedName,
ClassKind.CLASS,
Visibilities.PRIVATE,
Modality.FINAL,
isCompanion = false,
isInner = false,
isData = false,
isExternal = false,
isInline = false
).apply {
it.bind(this)
parent = this@FunctionReferenceBuilder.parent
createParameterDeclarations()
}
}
private val functionReferenceThis = functionReferenceClass.thisReceiver!!
private val argumentToPropertiesMap = boundFunctionParameters.associate {
it to createField(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
it.type,
it.name,
isMutable = false,
owner = functionReferenceClass
)
}
private val kFunctionImplSymbol = symbols.kFunctionImpl
private val kFunctionImplConstructorSymbol = kFunctionImplSymbol.constructors.single()
val isKFunction = functionReference.type.classifierOrNull?.descriptor
?.getFunctionalClassKind() == FunctionClassDescriptor.Kind.KFunction
val isKFunction = functionReference.type.isKFunction()
fun build(): BuiltFunctionReference {
val startOffset = functionReference.startOffset
val endOffset = functionReference.endOffset
val superClassType = if (isKFunction) {
kFunctionImplSymbol.typeWith(irFunction.returnType)
kFunctionImplSymbol.typeWith(referencedFunction.returnType)
} else {
irBuiltIns.anyType
}
@@ -181,7 +200,7 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
}
val functionParameterTypes = unboundFunctionParameters.map { it.type }
val functionClassTypeParameters = functionParameterTypes + irFunction.returnType
val functionClassTypeParameters = functionParameterTypes + referencedFunction.returnType
superTypes += functionIrClass.symbol.typeWith(functionClassTypeParameters)
var suspendFunctionIrClass: IrClass? = null
@@ -190,136 +209,65 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
lastParameterType as IrSimpleType
// If the last parameter is Continuation<> inherit from SuspendFunction.
suspendFunctionIrClass = symbols.suspendFunctions[numberOfParameters - 1].owner
var suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) +
val suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) +
(lastParameterType.arguments.single().typeOrNull ?: irBuiltIns.anyNType)
superTypes += suspendFunctionIrClass.symbol.typeWith(suspendFunctionClassTypeParameters)
}
functionReferenceClassDescriptor = object : ClassDescriptorImpl(
/* containingDeclaration = */ containingDeclaration,
/* name = */ "${functionDescriptor.name}\$FUNCTION_REFERENCE\$${context.functionReferenceCount++}".synthesizedName,
/* modality = */ Modality.FINAL,
/* kind = */ ClassKind.CLASS,
/* superTypes = */ superTypes.map { it.toKotlinType() },
/* source = */ SourceElement.NO_SOURCE,
/* isExternal = */ false,
/* storageManager = */ LockBasedStorageManager.NO_LOCKS
) {
override fun getVisibility() = Visibilities.PRIVATE
}
functionReferenceClass = IrClassImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
descriptor = functionReferenceClassDescriptor
)
functionReferenceClass.parent = this.parent
val constructor = buildConstructor()
buildInvokeMethod(functionIrClass.simpleFunctions().single { it.name.asString() == "invoke" })
suspendFunctionIrClass?.let { buildInvokeMethod(it.simpleFunctions().single { it.name.asString() == "invoke" }) }
functionReferenceClass.superTypes += superTypes
functionReferenceClass.addFakeOverrides()
val constructorBuilder = createConstructorBuilder()
val invokeFunctionSymbol =
functionIrClass.simpleFunctions().single { it.name.asString() == "invoke" }.symbol
val invokeMethodBuilder = createInvokeMethodBuilder(invokeFunctionSymbol, functionReferenceClass)
var suspendInvokeMethodBuilder: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>? = null
if (suspendFunctionIrClass != null) {
val suspendInvokeFunctionSymbol =
suspendFunctionIrClass.simpleFunctions().single { it.name.asString() == "invoke" }.symbol
suspendInvokeMethodBuilder = createInvokeMethodBuilder(suspendInvokeFunctionSymbol, functionReferenceClass)
}
val memberScope = stub<MemberScope>("callable reference class")
functionReferenceClassDescriptor.initialize(
memberScope, setOf(constructorBuilder.symbol.descriptor), null)
functionReferenceClass.createParameterDeclarations()
functionReferenceThis = functionReferenceClass.thisReceiver!!.symbol
constructorBuilder.initialize()
functionReferenceClass.addChild(constructorBuilder.ir)
invokeMethodBuilder.initialize()
functionReferenceClass.addChild(invokeMethodBuilder.ir)
suspendInvokeMethodBuilder?.let {
it.initialize()
functionReferenceClass.addChild(it.ir)
}
functionReferenceClass.setSuperSymbolsAndAddFakeOverrides(superTypes)
return BuiltFunctionReference(functionReferenceClass, constructorBuilder.ir)
return BuiltFunctionReference(functionReferenceClass, constructor)
}
private fun createConstructorBuilder()
= object : SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() {
private fun buildConstructor() = WrappedClassConstructorDescriptor().let {
IrConstructorImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
IrConstructorSymbolImpl(it),
Name.special("<init>"),
Visibilities.PUBLIC,
functionReferenceClass.defaultType,
isInline = false,
isExternal = false,
isPrimary = true
).apply {
it.bind(this)
parent = functionReferenceClass
functionReferenceClass.declarations += this
override fun buildSymbol() = IrConstructorSymbolImpl(
ClassConstructorDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor,
/* annotations = */ Annotations.EMPTY,
/* isPrimary = */ false,
/* source = */ SourceElement.NO_SOURCE
)
)
override fun doInitialize() {
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
val constructorParameters = boundFunctionParameters.mapIndexed { index, parameter ->
parameter.descriptor.copyAsValueParameter(descriptor, index)
}
descriptor.initialize(constructorParameters, Visibilities.PUBLIC)
descriptor.returnType = functionReferenceClassDescriptor.defaultType
}
override fun buildIr(): IrConstructor {
argumentToPropertiesMap = boundFunctionParameters.associate {
it.descriptor to buildField(it.name, it.type, false)
boundFunctionParameters.mapIndexedTo(valueParameters) { index, parameter ->
parameter.copyTo(this, DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, index,
type = parameter.type.substitute(typeArgumentsMap))
}
val startOffset = functionReference.startOffset
val endOffset = functionReference.endOffset
return IrConstructorImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
symbol = symbol,
returnType = functionReferenceClass.defaultType
).apply {
val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset)
boundFunctionParameters.mapIndexedTo(this.valueParameters) { index, parameter ->
parameter.copy(descriptor.valueParameters[index])
body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody {
if (!isKFunction)
+irDelegatingConstructorCall(irBuiltIns.anyClass.owner.constructors.single())
else +irDelegatingConstructorCall(kFunctionImplConstructorSymbol.owner).apply {
val stringType = irBuiltIns.stringType
val name = IrConstImpl(startOffset, endOffset, stringType,
IrConstKind.String, referencedFunction.name.asString())
putValueArgument(0, name)
val fqName = IrConstImpl(startOffset, endOffset, stringType, IrConstKind.String,
(functionReference.symbol.owner).fullName)
putValueArgument(1, fqName)
val bound = IrConstImpl.boolean(startOffset, endOffset, context.irBuiltIns.booleanType,
boundFunctionParameters.isNotEmpty())
putValueArgument(2, bound)
val needReceiver = boundFunctionParameters.singleOrNull()?.descriptor is ReceiverParameterDescriptor
val receiver = if (needReceiver) irGet(valueParameters.single()) else irNull()
putValueArgument(3, receiver)
putValueArgument(4, irKType(this@CallableReferenceLowering.context, referencedFunction.returnType))
}
body = irBuilder.irBlockBody {
if (!isKFunction) +irDelegatingConstructorCall(irBuiltIns.anyClass.owner.constructors.single())
else +IrDelegatingConstructorCallImpl(startOffset, endOffset,
context.irBuiltIns.unitType,
kFunctionImplConstructorSymbol, kFunctionImplConstructorSymbol.descriptor, 0).apply {
val stringType = irBuiltIns.stringType
val name = IrConstImpl(startOffset, endOffset, stringType,
IrConstKind.String, functionDescriptor.name.asString())
putValueArgument(0, name)
val fqName = IrConstImpl(startOffset, endOffset, stringType, IrConstKind.String,
(functionReference.symbol.owner).fullName)
putValueArgument(1, fqName)
val bound = IrConstImpl.boolean(startOffset, endOffset, context.irBuiltIns.booleanType,
boundFunctionParameters.isNotEmpty())
putValueArgument(2, bound)
val needReceiver = boundFunctionParameters.singleOrNull()?.descriptor is ReceiverParameterDescriptor
val receiver = if (needReceiver) irGet(valueParameters.single()) else irNull()
putValueArgument(3, receiver)
putValueArgument(4, irKType(this@CallableReferenceLowering.context, irFunction.returnType))
}
+IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, irBuiltIns.unitType)
// Save all arguments to fields.
boundFunctionParameters.forEachIndexed { index, parameter ->
+irSetField(irGet(functionReferenceThis.owner), argumentToPropertiesMap[parameter.descriptor]!!, irGet(valueParameters[index]))
}
+IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClass.symbol, irBuiltIns.unitType)
// Save all arguments to fields.
boundFunctionParameters.forEachIndexed { index, parameter ->
+irSetField(irGet(functionReferenceThis), argumentToPropertiesMap[parameter]!!, irGet(valueParameters[index]))
}
}
}
@@ -328,108 +276,65 @@ internal class CallableReferenceLowering(val context: Context): FileLoweringPass
private val IrFunction.fullName: String
get() = parent.fqNameSafe.child(Name.identifier(functionName)).asString()
private fun createInvokeMethodBuilder(superFunctionSymbol: IrSimpleFunctionSymbol, parent: IrClass)
= object : SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrSimpleFunction>() {
private fun buildInvokeMethod(superFunction: IrSimpleFunction) = WrappedSimpleFunctionDescriptor().let {
IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
IrSimpleFunctionSymbolImpl(it),
superFunction.name,
Visibilities.PRIVATE,
Modality.FINAL,
referencedFunction.returnType,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = superFunction.isSuspend
).apply {
it.bind(this)
val function = this
parent = functionReferenceClass
functionReferenceClass.declarations += function
val superFunctionDescriptor: FunctionDescriptor = superFunctionSymbol.descriptor
this.createDispatchReceiverParameter()
override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor,
/* annotations = */ Annotations.EMPTY,
/* name = */ Name.identifier("invoke"),
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE
)
)
override fun doInitialize() {
val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl
val valueParameters = superFunctionDescriptor.valueParameters
.map { it.copyAsValueParameter(descriptor, it.index) }
descriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ functionReferenceClassDescriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ valueParameters,
/* unsubstitutedReturnType = */ superFunctionDescriptor.returnType,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE).apply {
overriddenDescriptors += superFunctionDescriptor
isSuspend = superFunctionDescriptor.isSuspend
superFunction.valueParameters.mapIndexedTo(valueParameters) { index, parameter ->
parameter.copyTo(this, DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL, index,
type = parameter.type.substitute(typeArgumentsMap))
}
}
override fun buildIr(): IrSimpleFunction {
val startOffset = functionReference.startOffset
val endOffset = functionReference.endOffset
val ourSymbol = symbol
return IrFunctionImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
symbol = ourSymbol,
returnType = superFunctionSymbol.owner.returnType // FIXME: substitute
).apply {
overriddenSymbols += superFunction.symbol
val function = this
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
this.parent = parent
this.createDispatchReceiverParameter()
superFunctionSymbol.owner.valueParameters.mapTo(this.valueParameters) {
it.copy(descriptor.valueParameters[it.index]) // FIXME: substitute
}
body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn(
irCall(functionReference.symbol).apply {
var unboundIndex = 0
val unboundArgsSet = unboundFunctionParameters.toSet()
functionParameters.forEach {
val argument =
if (!unboundArgsSet.contains(it))
// Bound parameter - read from field.
irGetField(
irGet(function.dispatchReceiverParameter!!),
argumentToPropertiesMap[it.descriptor]!!
)
else {
if (ourSymbol.descriptor.isSuspend && unboundIndex == valueParameters.size)
// For suspend functions the last argument is continuation and it is implicit.
irCall(getContinuationSymbol.owner,
listOf(returnType))
else
irGet(valueParameters[unboundIndex++])
}
when (it) {
irFunction.dispatchReceiverParameter -> dispatchReceiver = argument
irFunction.extensionReceiverParameter -> extensionReceiver = argument
else -> putValueArgument(it.index, argument)
}
body = context.createIrBuilder(function.symbol, startOffset, endOffset).irBlockBody(startOffset, endOffset) {
+irReturn(
irCall(functionReference.symbol).apply {
var unboundIndex = 0
val unboundArgsSet = unboundFunctionParameters.toSet()
for (parameter in functionParameters) {
val argument =
if (!unboundArgsSet.contains(parameter))
// Bound parameter - read from field.
irGetField(
irGet(function.dispatchReceiverParameter!!),
argumentToPropertiesMap[parameter]!!
)
else {
if (function.isSuspend && unboundIndex == valueParameters.size)
// For suspend functions the last argument is continuation and it is implicit.
irCall(getContinuationSymbol.owner, listOf(returnType))
else
irGet(valueParameters[unboundIndex++])
}
when (parameter) {
referencedFunction.dispatchReceiverParameter -> dispatchReceiver = argument
referencedFunction.extensionReceiverParameter -> extensionReceiver = argument
else -> putValueArgument(parameter.index, argument)
}
assert(unboundIndex == valueParameters.size, { "Not all arguments of <invoke> are used" })
}
)
}
assert(unboundIndex == valueParameters.size) { "Not all arguments of <invoke> are used" }
}
)
}
}
}
private fun buildField(name: Name, type: IrType, isMutable: Boolean): IrField = createField(
functionReference.startOffset,
functionReference.endOffset,
type,
name,
isMutable,
DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
functionReferenceClassDescriptor
).also {
functionReferenceClass.addChild(it)
}
}
}
}
@@ -57,12 +57,11 @@ internal class DataClassOperatorsLowering(val context: Context): FunctionLowerin
extensionReceiver = argument
}
} else {
val tmp = scope.createTemporaryVariable(argument)
val call = irCall(newCallee, typeArguments).apply {
extensionReceiver = irGet(tmp)
}
irBlock(argument) {
+tmp
val tmp = irTemporary(argument)
val call = irCall(newCallee, typeArguments).apply {
extensionReceiver = irGet(tmp)
}
+irIfThenElse(call.type,
irEqeqeq(irGet(tmp), irNull()),
if (isToString)
@@ -71,7 +71,7 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
}
override fun visitField(declaration: IrField) {
(declaration.descriptor as WrappedPropertyDescriptor).bind(declaration)
(declaration.descriptor as WrappedFieldDescriptor).bind(declaration)
declaration.acceptChildrenVoid(this)
}
@@ -130,7 +130,7 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
WrappedClassDescriptor(descriptor.annotations, descriptor.source)
override fun remapDeclaredField(descriptor: PropertyDescriptor) =
WrappedPropertyDescriptor(descriptor.annotations, descriptor.source)
WrappedFieldDescriptor(descriptor.annotations, descriptor.source)
override fun remapDeclaredSimpleFunction(descriptor: FunctionDescriptor) =
WrappedSimpleFunctionDescriptor(descriptor.annotations, descriptor.source)
@@ -7,6 +7,7 @@ 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.descriptors.WrappedFieldDescriptor
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.backend.konan.Context
@@ -19,7 +20,6 @@ import org.jetbrains.kotlin.backend.konan.SYNTHETIC_OFFSET
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
@@ -33,19 +33,15 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.replace
internal class PropertyDelegationLowering(val context: Context) : FileLoweringPass {
private var tempIndex = 0
@@ -59,7 +55,7 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
val classSymbol =
if (isLocal) {
assert(receiverTypes.isEmpty(), { "Local delegated property cannot have explicit receiver" })
assert(receiverTypes.isEmpty()) { "Local delegated property cannot have explicit receiver" }
when {
isMutable -> symbols.kLocalDelegatedMutablePropertyImpl
else -> symbols.kLocalDelegatedPropertyImpl
@@ -87,29 +83,37 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
return classSymbol.constructors.single() to arguments
}
private fun ClassDescriptor.replace(vararg type: KotlinType): SimpleType {
return this.defaultType.replace(type.map(::TypeProjectionImpl))
}
override fun lower(irFile: IrFile) {
val kProperties = mutableMapOf<VariableDescriptorWithAccessors, Pair<IrExpression, Int>>()
val arrayClass = context.ir.symbols.array.owner
val arrayItemGetter = arrayClass.functions.single { it.descriptor.name == Name.identifier("get") }
val arrayItemGetter = arrayClass.functions.single { it.name == Name.identifier("get") }
val anyType = context.irBuiltIns.anyType
val kPropertyImplType = context.ir.symbols.kProperty1Impl.typeWith(anyType, anyType)
val kPropertiesFieldType: IrType = context.ir.symbols.array.typeWith(kPropertyImplType)
val kPropertiesField = IrFieldImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
createKPropertiesFieldDescriptor(irFile.packageFragmentDescriptor,
kPropertiesFieldType.toKotlinType()
),
kPropertiesFieldType
)
val kPropertiesField = WrappedFieldDescriptor(
Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.sharedImmutable.defaultType,
emptyMap(), SourceElement.NO_SOURCE)))
).let {
IrFieldImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION,
IrFieldSymbolImpl(it),
"KPROPERTIES".synthesizedName,
kPropertiesFieldType,
Visibilities.PRIVATE,
isFinal = true,
isExternal = false,
isStatic = true
).apply {
it.bind(this)
parent = irFile
}
}
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
@@ -135,18 +139,20 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
val irBuilder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, startOffset, endOffset)
irBuilder.run {
val receiversCount = listOf(expression.dispatchReceiver, expression.extensionReceiver).count { it != null }
if (receiversCount == 1) // Has receiver.
return createKProperty(expression, this)
else if (receiversCount == 2)
throw AssertionError("Callable reference to properties with two receivers is not allowed: ${expression.descriptor}")
else { // Cache KProperties with no arguments.
val field = kProperties.getOrPut(expression.descriptor) {
createKProperty(expression, this) to kProperties.size
}
return when (receiversCount) {
1 -> createKProperty(expression, this) // Has receiver.
return irCall(arrayItemGetter).apply {
dispatchReceiver = irGetField(null, kPropertiesField)
putValueArgument(0, irInt(field.second))
2 -> error("Callable reference to properties with two receivers is not allowed: ${expression.descriptor}")
else -> { // Cache KProperties with no arguments.
val field = kProperties.getOrPut(expression.descriptor) {
createKProperty(expression, this) to kProperties.size
}
irCall(arrayItemGetter).apply {
dispatchReceiver = irGetField(null, kPropertiesField)
putValueArgument(0, irInt(field.second))
}
}
}
}
@@ -188,11 +194,8 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
// TODO: move to object for lazy initialization.
irFile.declarations.add(0, kPropertiesField.apply {
initializer = IrExpressionBodyImpl(startOffset, endOffset,
context.createArrayOfExpression(kPropertyImplType, initializers,
startOffset, endOffset))
context.createArrayOfExpression(startOffset, endOffset, kPropertyImplType, initializers))
})
kPropertiesField.parent = irFile
}
}
@@ -235,15 +238,18 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
type = getterKFunctionType,
symbol = expression.getter!!,
descriptor = getter.descriptor,
typeArgumentsCount = 0
typeArgumentsCount = getter.typeParameters.size,
valueArgumentsCount = getter.valueParameters.size
).apply {
this.dispatchReceiver = dispatchReceiver?.let { irGet(it) }
this.extensionReceiver = extensionReceiver?.let { irGet(it) }
for (index in 0 until expression.typeArgumentsCount)
putTypeArgument(index, expression.getTypeArgument(index))
}
}
val setterCallableReference = expression.setter?.owner?.let {
if (!isKMutablePropertyType(expression.type.toKotlinType())) null
val setterCallableReference = expression.setter?.owner?.let { setter ->
if (!isKMutablePropertyType(expression.type)) null
else {
val setterKFunctionType = this@PropertyDelegationLowering.context.ir.symbols.getKFunctionType(
context.irBuiltIns.unitType,
@@ -254,11 +260,14 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
endOffset = endOffset,
type = setterKFunctionType,
symbol = expression.setter!!,
descriptor = it.descriptor,
typeArgumentsCount = 0
descriptor = setter.descriptor,
typeArgumentsCount = setter.typeParameters.size,
valueArgumentsCount = setter.valueParameters.size
).apply {
this.dispatchReceiver = dispatchReceiver?.let { irGet(it) }
this.extensionReceiver = extensionReceiver?.let { irGet(it) }
for (index in 0 until expression.typeArgumentsCount)
putTypeArgument(index, expression.getTypeArgument(index))
}
}
}
@@ -297,32 +306,20 @@ internal class PropertyDelegationLowering(val context: Context) : FileLoweringPa
}
}
private fun isKMutablePropertyType(type: KotlinType): Boolean {
val arguments = type.arguments
val expectedClassDescriptor = when (arguments.size) {
private fun isKMutablePropertyType(type: IrType): Boolean {
if (type !is IrSimpleType) return false
val expectedClass = when (type.arguments.size) {
0 -> return false
1 -> context.reflectionTypes.kMutableProperty0
2 -> context.reflectionTypes.kMutableProperty1
3 -> context.reflectionTypes.kMutableProperty2
1 -> context.ir.symbols.kMutableProperty0
2 -> context.ir.symbols.kMutableProperty1
3 -> context.ir.symbols.kMutableProperty2
else -> throw AssertionError("More than 2 receivers is not allowed")
}
return type == expectedClassDescriptor.defaultType.replace(arguments)
return type.classifier == expectedClass
}
private object DECLARATION_ORIGIN_KPROPERTIES_FOR_DELEGATION :
IrDeclarationOriginImpl("KPROPERTIES_FOR_DELEGATION")
private fun createKPropertiesFieldDescriptor(containingDeclaration: DeclarationDescriptor, fieldType: KotlinType): PropertyDescriptorImpl {
return PropertyDescriptorImpl.create(containingDeclaration,
Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.sharedImmutable.defaultType,
emptyMap(), SourceElement.NO_SOURCE))), Modality.FINAL, Visibilities.PRIVATE,
false, "KPROPERTIES".synthesizedName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE,
false, false, false, false, false, false).apply {
this.setType(fieldType, emptyList(), null, null)
this.initialize(null, null)
}
}
}
internal fun IrBuilderWithScope.irKType(context: KonanBackendContext, type: IrType): IrExpression {
@@ -8,7 +8,11 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
import org.jetbrains.kotlin.backend.common.ir.addSimpleDelegatingConstructor
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
@@ -17,8 +21,6 @@ import org.jetbrains.kotlin.backend.konan.DECLARATION_ORIGIN_ENUM
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.irasdescriptors.constructedClass
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
@@ -28,14 +30,17 @@ import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin.ARGUMENTS_REORDERIN
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager
internal class EnumSyntheticFunctionsBuilder(val context: Context) {
fun buildValuesExpression(startOffset: Int, endOffset: Int,
@@ -105,9 +110,7 @@ internal class EnumUsageLowering(val context: Context)
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
val descriptor = expression.descriptor as? FunctionDescriptor
?: return expression
if (descriptor.original != enumValuesDescriptor && descriptor.original != enumValueOfDescriptor)
if (expression.symbol != enumValuesSymbol && expression.symbol != enumValueOfSymbol)
return expression
val irClassSymbol = expression.getTypeArgument(0)!!.classifierOrNull as? IrClassSymbol
@@ -119,19 +122,17 @@ internal class EnumUsageLowering(val context: Context)
assert (irClass.kind == ClassKind.ENUM_CLASS)
return if (descriptor.original == enumValuesDescriptor) {
enumSyntheticFunctionsBuilder.buildValuesExpression(expression.startOffset, expression.endOffset, irClass)
} else {
val value = expression.getValueArgument(0)!!
enumSyntheticFunctionsBuilder.buildValueOfExpression(expression.startOffset, expression.endOffset, irClass, value)
}
return if (expression.symbol == enumValuesSymbol) {
enumSyntheticFunctionsBuilder.buildValuesExpression(expression.startOffset, expression.endOffset, irClass)
} else {
val value = expression.getValueArgument(0)!!
enumSyntheticFunctionsBuilder.buildValueOfExpression(expression.startOffset, expression.endOffset, irClass, value)
}
}
private val enumValueOfSymbol = context.ir.symbols.enumValueOf
private val enumValueOfDescriptor = enumValueOfSymbol.descriptor
private val enumValuesSymbol = context.ir.symbols.enumValues
private val enumValuesDescriptor = enumValuesSymbol.descriptor
private fun loadEnumEntry(startOffset: Int, endOffset: Int, enumClass: IrClass, name: Name): IrExpression {
val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(enumClass)
@@ -154,8 +155,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
override fun lower(irClass: IrClass) {
val descriptor = irClass.descriptor
if (descriptor.kind != ClassKind.ENUM_CLASS) return
if (irClass.kind != ClassKind.ENUM_CLASS) return
EnumClassTransformer(irClass).run()
}
@@ -166,10 +166,9 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
private inner class EnumClassTransformer(val irClass: IrClass) {
private val loweredEnum = context.specialDeclarationsFactory.getLoweredEnum(irClass)
private val loweredEnumConstructors = mutableMapOf<ClassConstructorDescriptor, IrConstructor>()
private val descriptorToIrConstructorWithDefaultArguments = mutableMapOf<ClassConstructorDescriptor, IrConstructor>()
private val defaultEnumEntryConstructors = mutableMapOf<ClassConstructorDescriptor, IrConstructor>()
private val loweredEnumConstructorParameters = mutableMapOf<ValueParameterDescriptor, ValueParameterDescriptor>()
private val loweredEnumConstructors = mutableMapOf<IrConstructor, IrConstructor>()
private val defaultEnumEntryConstructors = mutableMapOf<IrConstructor, IrConstructor>()
private val loweredEnumConstructorParameters = mutableMapOf<IrValueParameter, IrValueParameter>()
private val enumSyntheticFunctionsBuilder = EnumSyntheticFunctionsBuilder(context)
fun run() {
@@ -177,9 +176,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
lowerEnumConstructors(irClass)
lowerEnumEntriesClasses()
val defaultClass = createDefaultClassForEnumEntries()
lowerEnumClassBody()
if (defaultClass != null)
irClass.addChild(defaultClass)
lowerEnumClassBody(defaultClass)
createImplObject()
}
@@ -225,48 +222,44 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
private fun createDefaultClassForEnumEntries(): IrClass? {
if (!irClass.declarations.any({ it is IrEnumEntry && it.correspondingClass == null })) return null
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
val descriptor = irClass.descriptor
val defaultClassDescriptor = ClassDescriptorImpl(descriptor, "DEFAULT".synthesizedName, Modality.FINAL,
ClassKind.CLASS, listOf(descriptor.defaultType), SourceElement.NO_SOURCE, false, LockBasedStorageManager.NO_LOCKS)
val defaultClass = IrClassImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, defaultClassDescriptor)
defaultClass.createParameterDeclarations()
val constructors = mutableSetOf<ClassConstructorDescriptor>()
descriptor.constructors.forEach {
val loweredEnumIrConstructor = loweredEnumConstructors[it]!!
val loweredEnumConstructor = loweredEnumIrConstructor.descriptor
val constructor = defaultClass.addSimpleDelegatingConstructor(
loweredEnumIrConstructor,
context.irBuiltIns,
DECLARATION_ORIGIN_ENUM
)
val constructorDescriptor = constructor.descriptor
constructors.add(constructorDescriptor)
defaultEnumEntryConstructors.put(loweredEnumConstructor, constructor)
val irConstructor = descriptorToIrConstructorWithDefaultArguments[loweredEnumConstructor]
if (irConstructor != null) {
it.valueParameters.filter { it.declaresDefaultValue() }.forEach { argument ->
val loweredArgument = loweredEnumConstructor.valueParameters[argument.loweredIndex()]
val body = irConstructor.getDefault(loweredArgument)!!.deepCopyWithVariables()
body.transformChildrenVoid(ParameterMapper(constructor))
body.accept(SetDeclarationsParentVisitor, constructor)
constructor.putDefault(constructorDescriptor.valueParameters[loweredArgument.index], body)
}
if (!irClass.declarations.any { it is IrEnumEntry && it.correspondingClass == null }) return null
val defaultClass = WrappedClassDescriptor().let {
IrClassImpl(
irClass.startOffset, irClass.endOffset,
DECLARATION_ORIGIN_ENUM,
IrClassSymbolImpl(it),
"DEFAULT".synthesizedName,
ClassKind.CLASS,
Visibilities.PRIVATE,
Modality.FINAL,
isCompanion = false,
isInner = false,
isData = false,
isExternal = false,
isInline = false
).apply {
it.bind(this)
parent = irClass
irClass.declarations += this
createParameterDeclarations()
}
}
val memberScope = stub<MemberScope>("enum default class")
defaultClassDescriptor.initialize(memberScope, constructors, null)
for (superConstructor in irClass.constructors) {
val constructor = defaultClass.addSimpleDelegatingConstructor(superConstructor, context.irBuiltIns)
defaultEnumEntryConstructors[superConstructor] = constructor
defaultClass.setSuperSymbolsAndAddFakeOverrides(listOf(irClass.defaultType))
for (parameter in constructor.valueParameters) {
val defaultValue = superConstructor.valueParameters[parameter.index].defaultValue ?: continue
val body = defaultValue.deepCopyWithVariables()
body.transformChildrenVoid(ParameterMapper(superConstructor, constructor, false))
body.patchDeclarationParents(constructor)
parameter.defaultValue = body
}
}
defaultClass.superTypes += irClass.defaultType
defaultClass.addFakeOverrides()
return defaultClass
}
@@ -302,39 +295,42 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
++i
}
implObject.addChild(createSyntheticValuesPropertyDeclaration(enumEntries))
implObject.addChild(createValuesPropertyInitializer(enumEntries))
implObject.declarations += createSyntheticValuesPropertyDeclaration(enumEntries)
implObject.declarations += createValuesPropertyInitializer(enumEntries)
irClass.addChild(implObject)
irClass.declarations += implObject
}
private val genericCreateUninitializedInstanceSymbol = context.ir.symbols.createUninitializedInstance
private val genericCreateUninitializedInstanceDescriptor = genericCreateUninitializedInstanceSymbol.descriptor
private val createUninitializedInstance = context.ir.symbols.createUninitializedInstance.owner
private fun createSyntheticValuesPropertyDeclaration(enumEntries: List<IrEnumEntry>): IrPropertyImpl {
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
val irValuesInitializer = context.createArrayOfExpression(irClass.defaultType,
val irValuesInitializer = context.createArrayOfExpression(
startOffset, endOffset,
irClass.defaultType,
enumEntries
.sortedBy { it.descriptor.name }
.sortedBy { it.name }
.map {
val initializer = it.initializerExpression
val entryConstructorCall = when {
initializer is IrCall -> initializer
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL ->
initializer.statements.last() as IrCall
else -> error("Unexpected initializer: $initializer")
}
val entryConstructor = entryConstructorCall.symbol.owner as IrConstructor
val entryClass = entryConstructor.constructedClass
initializer is IrCall -> initializer
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL ->
initializer.statements.last() as IrCall
else -> error("Unexpected initializer: $initializer")
}
val entryClass = (entryConstructorCall.symbol.owner as IrConstructor).constructedClass
irCall(startOffset, endOffset,
genericCreateUninitializedInstanceSymbol.owner,
createUninitializedInstance,
listOf(entryClass.defaultType)
)
}, startOffset, endOffset)
}
)
val irField = loweredEnum.valuesField.apply {
initializer = IrExpressionBodyImpl(startOffset, endOffset, irValuesInitializer)
}
@@ -344,15 +340,13 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val receiver = IrGetObjectValueImpl(startOffset, endOffset,
loweredEnum.implObject.defaultType, loweredEnum.implObject.symbol)
val value = IrGetFieldImpl(
startOffset,
endOffset,
startOffset, endOffset,
loweredEnum.valuesField.symbol,
loweredEnum.valuesField.type,
receiver
)
val returnStatement = IrReturnImpl(
startOffset,
endOffset,
startOffset, endOffset,
context.irBuiltIns.nothingType,
loweredEnum.valuesGetter.symbol,
value
@@ -360,14 +354,14 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
getter.body = IrBlockBodyImpl(startOffset, endOffset, listOf(returnStatement))
return IrPropertyImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM,
false, loweredEnum.valuesField.descriptor, irField, getter, null).also {
it.parent = loweredEnum.implObject
false, loweredEnum.valuesField.descriptor, irField, getter, null).apply {
parent = loweredEnum.implObject
}
}
private val initInstanceSymbol = context.ir.symbols.initInstance
private val arrayGetSymbol = context.ir.symbols.array.functions.single { it.descriptor.name == Name.identifier("get") }
private val arrayGetSymbol = context.ir.symbols.array.functions.single { it.owner.name == Name.identifier("get") }
private val arrayType = context.ir.symbols.array.typeWith(irClass.defaultType)
@@ -376,17 +370,23 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val endOffset = irClass.endOffset
fun IrBlockBodyBuilder.initInstanceCall(instance: IrCall, constructor: IrCall): IrCall =
irCall(initInstanceSymbol).apply {
putValueArgument(0, instance)
putValueArgument(1, constructor)
}
irCall(initInstanceSymbol).apply {
putValueArgument(0, instance)
putValueArgument(1, constructor)
}
return IrAnonymousInitializerImpl(startOffset, endOffset, DECLARATION_ORIGIN_ENUM, loweredEnum.implObject.descriptor).apply {
parent = irClass
val implObject = loweredEnum.implObject
return IrAnonymousInitializerImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrAnonymousInitializerSymbolImpl(WrappedClassDescriptor())
).apply {
parent = implObject
body = context.createIrBuilder(symbol, startOffset, endOffset).irBlockBody(irClass) {
val instances = irTemporary(irGetField(irGet(loweredEnum.implObject.thisReceiver!!), loweredEnum.valuesField))
val receiver = implObject.thisReceiver!!
val instances = irTemporary(irGetField(irGet(receiver), loweredEnum.valuesField))
enumEntries
.sortedBy { it.descriptor.name }
.sortedBy { it.name }
.withIndex()
.forEach {
val instance = irCall(arrayGetSymbol).apply {
@@ -394,19 +394,22 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
putValueArgument(0, irInt(it.index))
}
val initializer = it.value.initializerExpression!!
initializer.patchDeclarationParents(implObject)
when {
initializer is IrCall -> +initInstanceCall(instance, initializer)
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> {
val statements = initializer.statements
val constructorCall = statements.last() as IrCall
statements[statements.lastIndex] = initInstanceCall(instance, constructorCall)
+initializer
}
else -> error("Unexpected initializer: $initializer")
}
}
+irCall(this@EnumClassLowering.context.ir.symbols.freeze, listOf(arrayType)).apply {
extensionReceiver = irGet(loweredEnum.implObject.thisReceiver!!)
extensionReceiver = irGet(receiver)
}
}
}
@@ -456,85 +459,75 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
private fun transformEnumConstructor(enumConstructor: IrConstructor): IrConstructor {
val loweredEnumConstructor = lowerEnumConstructor(enumConstructor)
enumConstructor.descriptor.valueParameters.filter { it.declaresDefaultValue() }.forEach {
val body = enumConstructor.getDefault(it)!!
body.transformChildrenVoid(object: IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
val descriptor = expression.descriptor
when (descriptor) {
is ValueParameterDescriptor -> {
val parameter = loweredEnumConstructor.valueParameters[descriptor.loweredIndex()]
return IrGetValueImpl(expression.startOffset,
expression.endOffset,
parameter.type,
parameter.symbol)
}
}
return expression
}
})
loweredEnumConstructor.valueParameters[it.loweredIndex()].defaultValue = body
descriptorToIrConstructorWithDefaultArguments[loweredEnumConstructor.descriptor] = loweredEnumConstructor
for (parameter in enumConstructor.valueParameters) {
val defaultValue = parameter.defaultValue ?: continue
defaultValue.transformChildrenVoid(ParameterMapper(enumConstructor, loweredEnumConstructor, true))
loweredEnumConstructor.valueParameters[parameter.loweredIndex].defaultValue = defaultValue
defaultValue.patchDeclarationParents(loweredEnumConstructor)
}
return loweredEnumConstructor
}
private fun lowerEnumConstructor(enumConstructor: IrConstructor): IrConstructorImpl {
val loweredConstructorDescriptor = ClassConstructorDescriptorImpl.createSynthesized(
enumConstructor.descriptor.containingDeclaration,
enumConstructor.descriptor.annotations,
enumConstructor.descriptor.isPrimary,
enumConstructor.descriptor.source
)
val valueParameters =
listOf(
loweredConstructorDescriptor.createValueParameter(
0,
"name",
context.irBuiltIns.stringType,
enumConstructor.startOffset,
enumConstructor.endOffset
),
loweredConstructorDescriptor.createValueParameter(
1,
"ordinal",
context.irBuiltIns.intType,
enumConstructor.startOffset,
enumConstructor.endOffset
)
) +
enumConstructor.valueParameters.map {
val descriptor = it.descriptor as ValueParameterDescriptor
val loweredValueParameterDescriptor = descriptor.copy(
loweredConstructorDescriptor,
it.name,
descriptor.loweredIndex()
)
loweredEnumConstructorParameters[descriptor] = loweredValueParameterDescriptor
it.copy(loweredValueParameterDescriptor)
}
loweredConstructorDescriptor.initialize(
valueParameters.map { it.descriptor as ValueParameterDescriptor },
Visibilities.PROTECTED
)
loweredConstructorDescriptor.returnType = enumConstructor.descriptor.returnType
val loweredEnumConstructor = IrConstructorImpl(
enumConstructor.startOffset, enumConstructor.endOffset, enumConstructor.origin,
loweredConstructorDescriptor,
enumConstructor.returnType,
enumConstructor.body!!
)
loweredEnumConstructor.valueParameters += valueParameters
loweredEnumConstructor.parent = enumConstructor.parent
loweredEnumConstructors[enumConstructor.descriptor] = loweredEnumConstructor
return loweredEnumConstructor
}
private fun lowerEnumClassBody() {
irClass.transformChildrenVoid(EnumClassBodyTransformer())
private fun lowerEnumConstructor(constructor: IrConstructor): IrConstructorImpl {
val startOffset = constructor.startOffset
val endOffset = constructor.endOffset
val loweredConstructor = WrappedClassConstructorDescriptor(
constructor.descriptor.annotations,
constructor.descriptor.source
).let {
IrConstructorImpl(
startOffset, endOffset,
constructor.origin,
IrConstructorSymbolImpl(it),
constructor.name,
Visibilities.PROTECTED,
constructor.returnType,
isInline = false,
isExternal = false,
isPrimary = constructor.isPrimary
).apply {
it.bind(this)
parent = constructor.parent
body = constructor.body!! // Will be transformed later.
}
}
fun createSynthesizedValueParameter(index: Int, name: String, type: IrType) =
WrappedValueParameterDescriptor().let {
IrValueParameterImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ENUM,
IrValueParameterSymbolImpl(it),
Name.identifier(name),
index,
type,
varargElementType = null,
isCrossinline = false,
isNoinline = false
).apply {
it.bind(this)
parent = loweredConstructor
}
}
loweredConstructor.valueParameters += createSynthesizedValueParameter(0, "name", context.irBuiltIns.stringType)
loweredConstructor.valueParameters += createSynthesizedValueParameter(1, "ordinal", context.irBuiltIns.intType)
constructor.valueParameters.mapTo(loweredConstructor.valueParameters) {
it.copyTo(loweredConstructor, index = it.loweredIndex).apply {
loweredEnumConstructorParameters[it] = this
}
}
loweredEnumConstructors[constructor] = loweredConstructor
return loweredConstructor
}
private fun lowerEnumClassBody(defaultClass: IrClass?) {
irClass.transformChildrenVoid(EnumClassBodyTransformer(defaultClass))
// Enum entries's classes have already been pulled out to the upper level - clear them up.
irClass.declarations.filterIsInstance<IrEnumEntry>().forEach { it.correspondingClass = null }
}
private inner class InEnumClassConstructor(val enumClassConstructor: IrConstructor) :
@@ -544,11 +537,12 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val endOffset = enumConstructorCall.endOffset
val origin = enumConstructorCall.origin
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset,
val result = IrDelegatingConstructorCallImpl(
startOffset, endOffset,
context.irBuiltIns.unitType,
enumConstructorCall.symbol, enumConstructorCall.descriptor, enumConstructorCall.typeArgumentsCount)
enumConstructorCall.symbol)
assert(result.descriptor.valueParameters.size == 2) {
assert(result.symbol.owner.valueParameters.size == 2) {
"Enum(String, Int) constructor call expected:\n${result.dump()}"
}
@@ -570,16 +564,18 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
override fun transform(delegatingConstructorCall: IrDelegatingConstructorCall): IrExpression {
val descriptor = delegatingConstructorCall.descriptor
val startOffset = delegatingConstructorCall.startOffset
val endOffset = delegatingConstructorCall.endOffset
val loweredDelegatedConstructor = loweredEnumConstructors.getOrElse(descriptor) {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $descriptor")
val delegatingConstructor = delegatingConstructorCall.symbol.owner
val loweredDelegatingConstructor = loweredEnumConstructors.getOrElse(delegatingConstructor) {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $delegatingConstructor")
}
val result = IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.unitType,
loweredDelegatedConstructor.symbol, loweredDelegatedConstructor.descriptor, 0)
val result = IrDelegatingConstructorCallImpl(
startOffset, endOffset,
context.irBuiltIns.unitType,
loweredDelegatingConstructor.symbol)
val firstParameter = enumClassConstructor.valueParameters[0]
result.putValueArgument(0,
@@ -588,25 +584,26 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
result.putValueArgument(1,
IrGetValueImpl(startOffset, endOffset, secondParameter.type, secondParameter.symbol))
descriptor.valueParameters.forEach { valueParameter ->
result.putValueArgument(valueParameter.loweredIndex(), delegatingConstructorCall.getValueArgument(valueParameter))
delegatingConstructor.valueParameters.forEach {
result.putValueArgument(it.loweredIndex, delegatingConstructorCall.getValueArgument(it.index))
}
return result
}
}
private abstract inner class InEnumEntry(private val enumEntry: ClassDescriptor) : EnumConstructorCallTransformer {
private abstract inner class InEnumEntry(private val enumEntry: IrEnumEntry) : EnumConstructorCallTransformer {
override fun transform(enumConstructorCall: IrEnumConstructorCall): IrExpression {
val name = enumEntry.name.asString()
val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry)
val ordinal = context.specialDeclarationsFactory.getEnumEntryOrdinal(enumEntry.descriptor)
val descriptor = enumConstructorCall.descriptor
val startOffset = enumConstructorCall.startOffset
val endOffset = enumConstructorCall.endOffset
val loweredConstructor = loweredEnumConstructors.getOrElse(descriptor) {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $descriptor")
val enumConstructor = enumConstructorCall.symbol.owner
val loweredConstructor = loweredEnumConstructors.getOrElse(enumConstructor) {
throw AssertionError("Constructor called in enum entry initializer should've been lowered: $enumConstructor")
}
val result = createConstructorCall(startOffset, endOffset, loweredConstructor.symbol)
@@ -616,9 +613,8 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
result.putValueArgument(1,
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, ordinal))
descriptor.valueParameters.forEach { valueParameter ->
val i = valueParameter.index
result.putValueArgument(i + 2, enumConstructorCall.getValueArgument(i))
enumConstructor.valueParameters.forEach {
result.putValueArgument(it.loweredIndex, enumConstructorCall.getValueArgument(it.index))
}
return result
@@ -631,7 +627,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
abstract fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrMemberAccessExpression
}
private inner class InEnumEntryClassConstructor(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) {
private inner class InEnumEntryClassConstructor(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) {
override fun createConstructorCall(
startOffset: Int,
endOffset: Int,
@@ -640,25 +636,23 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
startOffset,
endOffset,
context.irBuiltIns.unitType,
loweredConstructor,
loweredConstructor.descriptor,
0
loweredConstructor
)
}
private inner class InEnumEntryInitializer(enumEntry: ClassDescriptor) : InEnumEntry(enumEntry) {
private inner class InEnumEntryInitializer(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) {
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol): IrCall {
val irConstructorSymbol = defaultEnumEntryConstructors[loweredConstructor.descriptor]?.symbol
val irConstructorSymbol = defaultEnumEntryConstructors[loweredConstructor.owner]?.symbol
?: loweredConstructor
return IrCallImpl(startOffset, endOffset, irConstructorSymbol.owner.returnType, irConstructorSymbol)
}
}
private inner class EnumClassBodyTransformer : IrElementTransformerVoid() {
private inner class EnumClassBodyTransformer(val defaultClass: IrClass?) : IrElementTransformerVoid() {
private var enumConstructorCallTransformer: EnumConstructorCallTransformer? = null
override fun visitClass(declaration: IrClass): IrStatement {
if (declaration.descriptor.kind == ClassKind.ENUM_CLASS)
if (declaration.kind == ClassKind.ENUM_CLASS || declaration == defaultClass)
return declaration
return super.visitClass(declaration)
}
@@ -666,27 +660,25 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
override fun visitEnumEntry(declaration: IrEnumEntry): IrStatement {
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
enumConstructorCallTransformer = InEnumEntryInitializer(declaration.descriptor)
enumConstructorCallTransformer = InEnumEntryInitializer(declaration)
var result: IrEnumEntry = IrEnumEntryImpl(declaration.startOffset, declaration.endOffset, declaration.origin,
declaration.descriptor, null, declaration.initializerExpression)
result = super.visitEnumEntry(result) as IrEnumEntry
declaration.initializerExpression = declaration.initializerExpression?.transform(this, data = null)
enumConstructorCallTransformer = null
return result
return declaration
}
override fun visitConstructor(declaration: IrConstructor): IrStatement {
val constructorDescriptor = declaration.descriptor
val containingClass = constructorDescriptor.containingDeclaration
val containingClass = declaration.parentAsClass
// TODO local (non-enum) class in enum class constructor?
val previous = enumConstructorCallTransformer
if (containingClass.kind == ClassKind.ENUM_ENTRY) {
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
enumConstructorCallTransformer = InEnumEntryClassConstructor(containingClass)
val entry = irClass.declarations.filterIsInstance<IrEnumEntry>().single { it.correspondingClass == containingClass }
enumConstructorCallTransformer = InEnumEntryClassConstructor(entry)
} else if (containingClass.kind == ClassKind.ENUM_CLASS) {
assert(enumConstructorCallTransformer == null) { "Nested enum entry initialization:\n${declaration.dump()}" }
enumConstructorCallTransformer = InEnumClassConstructor(declaration)
@@ -703,7 +695,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
expression.transformChildrenVoid(this)
val callTransformer = enumConstructorCallTransformer ?:
throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump())
throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump())
return callTransformer.transform(expression)
@@ -712,9 +704,9 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
expression.transformChildrenVoid(this)
if (expression.descriptor.containingDeclaration.kind == ClassKind.ENUM_CLASS) {
if (expression.symbol.owner.parentAsClass.kind == ClassKind.ENUM_CLASS) {
val callTransformer = enumConstructorCallTransformer ?:
throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump())
throw AssertionError("Enum constructor call outside of enum entry initialization or enum class constructor:\n" + irClass.dump())
return callTransformer.transform(expression)
}
@@ -722,34 +714,36 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
}
override fun visitGetValue(expression: IrGetValue): IrExpression {
val loweredParameter = loweredEnumConstructorParameters[expression.descriptor]
if (loweredParameter != null) {
val loweredEnumConstructor = loweredEnumConstructors[expression.descriptor.containingDeclaration]!!
val loweredIrParameter = loweredEnumConstructor.valueParameters[loweredParameter.index]
assert(loweredIrParameter.descriptor == loweredParameter)
return IrGetValueImpl(expression.startOffset, expression.endOffset, loweredIrParameter.type,
loweredIrParameter.symbol, expression.origin)
val parameter = expression.symbol.owner
val loweredParameter = loweredEnumConstructorParameters[parameter]
return if (loweredParameter == null) {
expression
} else {
return expression
IrGetValueImpl(expression.startOffset, expression.endOffset, loweredParameter.type,
loweredParameter.symbol, expression.origin)
}
}
}
}
}
private fun ValueParameterDescriptor.loweredIndex(): Int = index + 2
private val IrValueParameter.loweredIndex: Int get() = index + 2
private class ParameterMapper(superConstructor: IrConstructor,
val constructor: IrConstructor,
val useLoweredIndex: Boolean) : IrElementTransformerVoid() {
private val valueParameters = superConstructor.valueParameters.toSet()
private class ParameterMapper(val originalConstructor: IrConstructor) : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
val descriptor = expression.descriptor
when (descriptor) {
is ValueParameterDescriptor -> {
val parameter = originalConstructor.valueParameters[descriptor.index]
return IrGetValueImpl(expression.startOffset,
expression.endOffset,
parameter.type,
parameter.symbol)
}
val superParameter = expression.symbol.owner as? IrValueParameter ?: return expression
if (valueParameters.contains(superParameter)) {
val index = if (useLoweredIndex) superParameter.loweredIndex else superParameter.index
val parameter = constructor.valueParameters[index]
return IrGetValueImpl(
expression.startOffset, expression.endOffset,
parameter.type,
parameter.symbol)
}
return expression
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor
import org.jetbrains.kotlin.backend.common.peek
import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push
@@ -16,11 +17,11 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.types.getClass
import org.jetbrains.kotlin.ir.util.getArguments
@@ -87,24 +88,33 @@ internal class EnumWhenLowering(private val context: Context) : IrElementTransfo
return expression
}
private fun createEnumOrdinalVariable(enumVariable: IrVariable): IrVariable {
val ordinalPropertyGetter = context.ir.symbols.enum.getPropertyGetter("ordinal")!!
val getOrdinal = IrCallImpl(
// Create temporary variable for subject's ordinal.
private fun createEnumOrdinalVariable(enumVariable: IrVariable) = WrappedVariableDescriptor().let {
IrVariableImpl(
enumVariable.startOffset, enumVariable.endOffset,
ordinalPropertyGetter.owner.returnType,
ordinalPropertyGetter
IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
IrVariableSymbolImpl(it),
Name.identifier(enumVariable.name.asString() + "_ordinal"),
context.irBuiltIns.intType,
isVar = false,
isConst = false,
isLateinit = false
).apply {
dispatchReceiver = IrGetValueImpl(
it.bind(this)
parent = enumVariable.parent
val ordinalPropertyGetter = context.ir.symbols.enum.getPropertyGetter("ordinal")!!
initializer = IrCallImpl(
enumVariable.startOffset, enumVariable.endOffset,
enumVariable.type, enumVariable.symbol
)
ordinalPropertyGetter.owner.returnType,
ordinalPropertyGetter
).apply {
dispatchReceiver = IrGetValueImpl(
enumVariable.startOffset, enumVariable.endOffset,
enumVariable.type, enumVariable.symbol
)
}
}
// Create temporary variable for subject's ordinal.
val ordinalDescriptor = IrTemporaryVariableDescriptorImpl(enumVariable.descriptor.containingDeclaration,
Name.identifier(enumVariable.name.asString() + "_ordinal"), context.builtIns.intType)
return IrVariableImpl(enumVariable.startOffset, enumVariable.endOffset,
IrDeclarationOrigin.IR_TEMPORARY_VARIABLE, ordinalDescriptor,
context.irBuiltIns.intType, getOrdinal)
}
override fun visitCall(expression: IrCall): IrExpression {
@@ -7,16 +7,13 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedVariableDescriptor
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl
import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrReturnTargetSymbol
@@ -25,17 +22,15 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.builders.irGet
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.symbols.impl.IrVariableSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.setDeclarationsParent
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.isUnit
internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, IrElementTransformerVoidWithContext() {
private val symbols get() = context.ir.symbols
private val symbols = context.ir.symbols
private interface HighLevelJump {
fun toIr(context: Context, startOffset: Int, endOffset: Int, value: IrExpression): IrExpression
@@ -66,7 +61,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
private abstract class Scope
private class ReturnableScope(val descriptor: CallableDescriptor): Scope()
private class ReturnableScope(val symbol: IrReturnTargetSymbol): Scope()
private class LoopScope(val loop: IrLoop): Scope()
@@ -92,7 +87,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
}
override fun visitFunctionNew(declaration: IrFunction): IrStatement {
using(ReturnableScope(declaration.descriptor)) {
using(ReturnableScope(declaration.symbol)) {
return super.visitFunctionNew(declaration)
}
}
@@ -101,7 +96,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
if (expression !is IrReturnableBlockImpl)
return super.visitContainerExpression(expression)
using(ReturnableScope(expression.descriptor)) {
using(ReturnableScope(expression.symbol)) {
return super.visitContainerExpression(expression)
}
}
@@ -142,7 +137,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
expression.transformChildrenVoid(this)
return performHighLevelJump(
targetScopePredicate = { it is ReturnableScope && it.descriptor == expression.returnTarget },
targetScopePredicate = { it is ReturnableScope && it.symbol == expression.returnTargetSymbol },
jump = Return(expression.returnTargetSymbol),
startOffset = expression.startOffset,
endOffset = expression.endOffset,
@@ -184,7 +179,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
val currentTryScope = tryScopes[index]
currentTryScope.jumps.getOrPut(jump) {
val type = (jump as? Return)?.target?.owner?.returnType ?: value.type
val symbol = getIrReturnableBlockSymbol(jump.toString(), type)
val symbol = IrReturnableBlockSymbolImpl(WrappedSimpleFunctionDescriptor())
with(currentTryScope) {
irBuilder.run {
val inlinedFinally = irInlineFinally(symbol, type, expression, finallyExpression)
@@ -223,14 +218,21 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
type = context.irBuiltIns.nothingType
)
val transformedFinallyExpression = finallyExpression.transform(transformer, null)
val parameter = IrTemporaryVariableDescriptorImpl(
containingDeclaration = currentScope!!.scope.scopeOwner,
name = Name.identifier("t"),
outType = context.builtIns.throwable.defaultType
)
val catchParameter = IrVariableImpl(
startOffset, endOffset, IrDeclarationOrigin.CATCH_PARAMETER, parameter,
symbols.throwable.owner.defaultType)
val catchParameter = WrappedVariableDescriptor().let {
IrVariableImpl(
startOffset, endOffset,
IrDeclarationOrigin.CATCH_PARAMETER,
IrVariableSymbolImpl(it),
Name.identifier("t"),
symbols.throwable.owner.defaultType,
isVar = false,
isConst = false,
isLateinit = false
).apply {
it.bind(this)
parent = this@run.parent
}
}
val syntheticTry = IrTryImpl(
startOffset = startOffset,
@@ -240,7 +242,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
catches = listOf(
irCatch(catchParameter).apply {
result = irBlock {
+finallyExpression.copy()
+copy(finallyExpression)
+irThrow(irGet(catchParameter))
}
}),
@@ -248,7 +250,7 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
)
using(TryScope(syntheticTry, transformedFinallyExpression, this)) {
val fallThroughType = aTry.type
val fallThroughSymbol = getIrReturnableBlockSymbol("fallThrough", fallThroughType)
val fallThroughSymbol = IrReturnableBlockSymbolImpl(WrappedSimpleFunctionDescriptor())
val transformedResult = aTry.tryResult.transform(transformer, null)
transformedTry.tryResult = irReturn(fallThroughSymbol, transformedResult)
for (aCatch in aTry.catches) {
@@ -264,39 +266,32 @@ internal class FinallyBlocksLowering(val context: Context): FileLoweringPass, Ir
private fun IrBuilderWithScope.irInlineFinally(symbol: IrReturnableBlockSymbol, type: IrType,
value: IrExpression,
finallyExpression: IrExpression): IrExpression {
val returnType = symbol.descriptor.returnType!!
return when {
returnType.isUnit() || returnType.isNothing() -> irBlock(value, null, type) {
val returnTypeClassifier = (type as? IrSimpleType)?.classifier
return when (returnTypeClassifier) {
symbols.unit, symbols.nothing -> irBlock(value, null, type) {
+irReturnableBlock(symbol, type) {
+value
}
+finallyExpression.copy()
+copy(finallyExpression)
}
else -> irBlock(value, null, type) {
val tmp = irTemporary(irReturnableBlock(symbol, type) {
+irReturn(symbol, value)
})
+finallyExpression.copy()
+copy(finallyExpression)
+irGet(tmp)
}
}
}
private fun getFakeFunctionDescriptor(name: String, returnType: KotlinType) =
SimpleFunctionDescriptorImpl.create(currentScope!!.scope.scopeOwner, Annotations.EMPTY, name.synthesizedName,
CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE).apply {
initialize(null, null, emptyList(), emptyList(), returnType, Modality.ABSTRACT, Visibilities.PRIVATE)
}
private fun getIrReturnableBlockSymbol(name: String, returnType: IrType): IrReturnableBlockSymbol =
IrReturnableBlockSymbolImpl(getFakeFunctionDescriptor(name, returnType.toKotlinType()))
private inline fun <reified T : IrElement> T.copy() = this.deepCopyWithVariables()
private inline fun <reified T : IrElement> IrBuilderWithScope.copy(element: T) =
element.deepCopyWithVariables().setDeclarationsParent(parent)
fun IrBuilderWithScope.irReturn(target: IrReturnTargetSymbol, value: IrExpression) =
IrReturnImpl(startOffset, endOffset, context.irBuiltIns.nothingType, target, value)
inline fun IrBuilderWithScope.irReturnableBlock(symbol: IrReturnableBlockSymbol, type: IrType, body: IrBlockBuilder.() -> Unit) =
private inline fun IrBuilderWithScope.irReturnableBlock(symbol: IrReturnableBlockSymbol,
type: IrType, body: IrBlockBuilder.() -> Unit) =
IrReturnableBlockImpl(startOffset, endOffset, type, symbol, null,
IrBlockBuilder(context, scope, startOffset, endOffset, null, type)
.block(body).statements)
@@ -10,6 +10,7 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.ir.ir2stringWhole
import org.jetbrains.kotlin.backend.common.lower.CoroutineIntrinsicLambdaOrigin
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionInvoke
@@ -150,7 +151,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerWithC
if (!callSite.descriptor.needsInlining)
return callSite
val functionDescriptor = callSite.descriptor.resolveFakeOverride().original
if (functionDescriptor == context.ir.symbols.isInitializedGetterDescriptor)
if (callSite.symbol == context.ir.symbols.isInitializedGetter)
return callSite
val callee = getFunctionDeclaration(functionDescriptor)
@@ -7,13 +7,12 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.isNonGeneratedAnnotation
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.irDelegatingConstructorCall
import org.jetbrains.kotlin.ir.declarations.*
@@ -21,10 +20,10 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.js.descriptorUtils.hasPrimaryConstructor
internal class InitializersLowering(val context: CommonBackendContext) : ClassLoweringPass {
@@ -41,8 +40,8 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
fun lowerInitializers() {
collectAndRemoveInitializers()
val initializerMethodSymbol = createInitializerMethod()
lowerConstructors(initializerMethodSymbol)
val initializeMethodSymbol = createInitializerMethod()
lowerConstructors(initializeMethodSymbol)
}
private fun collectAndRemoveInitializers() {
@@ -63,7 +62,9 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
val initializer = declaration.initializer ?: return declaration
val startOffset = initializer.startOffset
val endOffset = initializer.endOffset
initializers.add(IrBlockImpl(startOffset, endOffset, context.irBuiltIns.unitType, STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER,
initializers.add(IrBlockImpl(startOffset, endOffset,
context.irBuiltIns.unitType,
STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER,
listOf(
IrSetFieldImpl(startOffset, endOffset, declaration.symbol,
IrGetValueImpl(
@@ -72,7 +73,8 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
),
initializer.expression,
context.irBuiltIns.unitType,
STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER))))
STATEMENT_ORIGIN_ANONYMOUS_INITIALIZER)))
)
declaration.initializer = null
return declaration
}
@@ -88,52 +90,54 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
private fun createInitializerMethod(): IrSimpleFunctionSymbol? {
if (irClass.declarations.any { it is IrConstructor && it.isPrimary })
return null // Place initializers in the primary constructor.
val initializerMethodDescriptor = SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ irClass.descriptor,
/* annotations = */ Annotations.EMPTY,
/* name = */ "INITIALIZER".synthesizedName,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE)
initializerMethodDescriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ irClass.descriptor.thisAsReceiverParameter,
/* typeParameters = */ listOf(),
/* unsubstitutedValueParameters = */ listOf(),
/* returnType = */ context.builtIns.unitType,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE)
val startOffset = irClass.startOffset
val endOffset = irClass.endOffset
val initializer = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_ANONYMOUS_INITIALIZER,
initializerMethodDescriptor, context.irBuiltIns.unitType)
val initializeFun = WrappedSimpleFunctionDescriptor().let {
IrFunctionImpl(
startOffset, endOffset,
DECLARATION_ORIGIN_ANONYMOUS_INITIALIZER,
IrSimpleFunctionSymbolImpl(it),
"INITIALIZER".synthesizedName,
Visibilities.PRIVATE,
Modality.FINAL,
context.irBuiltIns.unitType,
isInline = false,
isSuspend = false,
isExternal = false,
isTailrec = false
).apply {
it.bind(this)
parent = irClass
irClass.declarations.add(this)
initializer.body = IrBlockBodyImpl(startOffset, endOffset, initializers)
createDispatchReceiverParameter()
initializer.parent = irClass
initializer.createDispatchReceiverParameter()
body = IrBlockBodyImpl(startOffset, endOffset, initializers)
}
}
initializers.forEach {
it.transformChildrenVoid(object : IrElementTransformerVoid() {
for (initializer in initializers) {
initializer.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
if (expression.symbol == irClass.thisReceiver!!.symbol) {
return IrGetValueImpl(
expression.startOffset,
expression.endOffset,
initializer.dispatchReceiverParameter!!.type,
initializer.dispatchReceiverParameter!!.symbol
initializeFun.dispatchReceiverParameter!!.type,
initializeFun.dispatchReceiverParameter!!.symbol
)
}
return expression
}
})
initializer.patchDeclarationParents(initializeFun)
}
irClass.declarations.add(initializer)
return initializer.symbol
return initializeFun.symbol
}
private fun lowerConstructors(initializerMethodSymbol: IrSimpleFunctionSymbol?) {
private fun lowerConstructors(initializeMethodSymbol: IrSimpleFunctionSymbol?) {
if (irClass.kind == ClassKind.ANNOTATION_CLASS) {
if (irClass.isNonGeneratedAnnotation()) return
@@ -158,14 +162,16 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
blockBody.statements.transformFlat {
when {
it is IrInstanceInitializerCall -> {
if (initializerMethodSymbol == null) {
assert(declaration.descriptor.isPrimary)
if (initializeMethodSymbol == null) {
assert(declaration.isPrimary)
for (initializer in initializers)
initializer.patchDeclarationParents(declaration)
initializers
} else {
val startOffset = it.startOffset
val endOffset = it.endOffset
listOf(IrCallImpl(startOffset, endOffset,
context.irBuiltIns.unitType, initializerMethodSymbol
context.irBuiltIns.unitType, initializeMethodSymbol
).apply {
dispatchReceiver = IrGetValueImpl(
startOffset, endOffset,
@@ -174,20 +180,24 @@ internal class InitializersLowering(val context: CommonBackendContext) : ClassLo
})
}
}
/**
* IR for kotlin.Any is:
* BLOCK_BODY
* DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
* INSTANCE_INITIALIZER_CALL classDescriptor='Any'
*
* to avoid possible recursion we manually reject body generation for Any.
*/
it is IrDelegatingConstructorCall && irClass.descriptor == context.builtIns.any
&& it.descriptor == declaration.descriptor -> listOf()
/**
* IR for kotlin.Any is:
* BLOCK_BODY
* DELEGATING_CONSTRUCTOR_CALL 'constructor Any()'
* INSTANCE_INITIALIZER_CALL classDescriptor='Any'
*
* to avoid possible recursion we manually reject body generation for Any.
*/
it is IrDelegatingConstructorCall
&& irClass.symbol == context.irBuiltIns.anyClass
&& it.symbol == declaration.symbol -> {
listOf()
}
else -> null
}
}
declaration.parent = irClass
return declaration
}
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.lower.callsSuper
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction
@@ -21,9 +20,12 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver
internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
override fun lower(irClass: IrClass) {
@@ -31,12 +33,10 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
}
private inner class InnerClassTransformer(val irClass: IrClass) {
val classDescriptor = irClass.descriptor
lateinit var outerThisFieldSymbol: IrFieldSymbol
fun lowerInnerClass() {
if (!irClass.descriptor.isInner) return
if (!irClass.isInner) return
createOuterThisField()
lowerOuterThisReferences()
@@ -84,10 +84,9 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
val implicitThisClass = expression.descriptor.getClassDescriptorForImplicitThis() ?:
return expression
val implicitThisClass = (expression.symbol.owner.parent as? IrClass) ?: return expression
if (implicitThisClass == classDescriptor) return expression
if (implicitThisClass == irClass) return expression
val constructorSymbol = currentFunction!!.scope.scopeOwnerSymbol as? IrConstructorSymbol
@@ -97,27 +96,27 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
var irThis: IrExpression
var innerClass: IrClass
if (constructorSymbol == null || constructorSymbol.descriptor.constructedClass != classDescriptor) {
if (constructorSymbol == null || constructorSymbol.owner.parentAsClass != irClass) {
innerClass = irClass
val currentIrFunction = currentFunction!!.scope.scopeOwnerSymbol.owner as IrFunction
val currentFunctionReceiver = currentIrFunction.dispatchReceiverParameter
val thisParameter = if (currentFunctionReceiver?.descriptor == irClass.thisReceiver!!.descriptor) {
currentFunctionReceiver
} else {
irClass.thisReceiver!!
}
val thisParameter =
if (currentFunctionReceiver?.type?.classifierOrNull == irClass.symbol)
currentFunctionReceiver
else
irClass.thisReceiver!!
irThis = IrGetValueImpl(startOffset, endOffset, thisParameter.type, thisParameter.symbol, origin)
} else {
// For constructor we have outer class as dispatchReceiverParameter.
innerClass = irClass.parent as? IrClass ?:
throw AssertionError("No containing class for inner class $classDescriptor")
throw AssertionError("No containing class for inner class ${irClass.dump()}")
val thisParameter = constructorSymbol.owner.dispatchReceiverParameter!!
irThis = IrGetValueImpl(startOffset, endOffset, thisParameter.type, thisParameter.symbol, origin)
}
while (innerClass.descriptor != implicitThisClass) {
while (innerClass != implicitThisClass) {
if (!innerClass.isInner) {
// Captured 'this' unrelated to inner classes nesting hierarchy, leave it as is -
// should be transformed by closures conversion.
@@ -134,23 +133,13 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
val outer = innerClass.parent
innerClass = outer as? IrClass ?:
throw AssertionError("Unexpected containing declaration for inner class ${innerClass.descriptor}: $outer")
throw AssertionError("Unexpected containing declaration for inner class ${innerClass.dump()}: $outer")
}
return irThis
}
})
}
private fun ValueDescriptor.getClassDescriptorForImplicitThis(): ClassDescriptor? {
if (this is ReceiverParameterDescriptor) {
val receiverValue = value
if (receiverValue is ImplicitClassReceiver) {
return receiverValue.classDescriptor
}
}
return null
}
}
}
@@ -9,10 +9,7 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.resolveFakeOverride
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.backend.konan.irasdescriptors.isReal
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
@@ -21,45 +18,29 @@ import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.IrPropertyReference
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
internal class LateinitLowering(
val context: Context,
private val generateParameterNameInAssertion: Boolean = false
) : FileLoweringPass {
private val isInitializedGetterDescriptor = context.ir.symbols.isInitializedGetterDescriptor
private val isInitializedGetter = context.ir.symbols.isInitializedGetter
override fun lower(irFile: IrFile) {
val lateinitPropertyToField = mutableMapOf<PropertyDescriptor, IrField>()
irFile.acceptVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitProperty(declaration: IrProperty) {
super.visitProperty(declaration)
if (declaration.isLateinit && declaration.descriptor.kind.isReal) {
lateinitPropertyToField[declaration.descriptor] = declaration.backingField!!
}
}
})
irFile.transformChildrenVoid(object : IrBuildingTransformer(context) {
override fun visitVariable(declaration: IrVariable): IrStatement {
declaration.transformChildrenVoid(this)
val descriptor = declaration.descriptor
if (!descriptor.isLateInit) return declaration
if (!declaration.isLateinit) return declaration
assert(declaration.initializer == null, { "'lateinit' modifier is not allowed for variables with initializer" })
assert(!KotlinBuiltIns.isPrimitiveType(descriptor.type), { "'lateinit' modifier is not allowed on primitive types" })
assert(declaration.initializer == null) {
"'lateinit' modifier is not allowed for variables with initializer"
}
builder.at(declaration).run {
declaration.initializer = irNull()
}
@@ -68,16 +49,14 @@ internal class LateinitLowering(
override fun visitGetValue(expression: IrGetValue): IrExpression {
val symbol = expression.symbol
val descriptor = symbol.descriptor as? VariableDescriptor
if (descriptor == null || !descriptor.isLateInit) return expression
if (symbol !is IrVariableSymbol || !symbol.owner.isLateinit) return expression
assert(!KotlinBuiltIns.isPrimitiveType(descriptor.type), { "'lateinit' modifier is not allowed on primitive types" })
builder.at(expression).run {
return irBlock(expression) {
// TODO: do data flow analysis to check if value is proved to be not-null.
+irIfThen(
irEqualsNull(irGet(expression.type, symbol)),
throwUninitializedPropertyAccessException(symbol)
throwUninitializedPropertyAccessException(symbol.owner.name)
)
+irGet(expression.type, symbol)
}
@@ -87,17 +66,17 @@ internal class LateinitLowering(
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
val descriptor = expression.descriptor
if (descriptor != isInitializedGetterDescriptor) return expression
if (expression.symbol != isInitializedGetter) return expression
val propertyReference = expression.extensionReceiver!! as IrPropertyReference
assert(propertyReference.extensionReceiver == null, { "'lateinit' modifier is not allowed on extension properties" })
val propertyDescriptor = propertyReference.descriptor.resolveFakeOverride().original
assert(propertyReference.extensionReceiver == null) {
"'lateinit' modifier is not allowed on extension properties"
}
val getter = propertyReference.getter?.owner ?: TODO(propertyReference.dump())
val property = getter.resolveFakeOverride().correspondingProperty!!
val type = propertyDescriptor.type
assert(!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" })
builder.at(expression).run {
val field = lateinitPropertyToField[propertyDescriptor]!!
val field = property.backingField!!
val fieldValue = irGetField(propertyReference.dispatchReceiver, field)
return irNotEquals(fieldValue, irNull())
}
@@ -106,13 +85,15 @@ internal class LateinitLowering(
override fun visitProperty(declaration: IrProperty): IrStatement {
declaration.transformChildrenVoid(this)
if (!declaration.descriptor.isLateInit || !declaration.descriptor.kind.isReal)
if (!declaration.isLateinit || !declaration.isReal)
return declaration
val backingField = declaration.backingField!!
transformGetter(backingField, declaration.getter!!)
assert(backingField.initializer == null, { "'lateinit' modifier is not allowed for properties with initializer" })
assert(backingField.initializer == null) {
"'lateinit' modifier is not allowed for properties with initializer"
}
val irBuilder = context.createIrBuilder(backingField.symbol, declaration.startOffset, declaration.endOffset)
irBuilder.run {
backingField.initializer = irExprBody(irNull())
@@ -122,8 +103,6 @@ internal class LateinitLowering(
}
private fun transformGetter(backingField: IrField, getter: IrFunction) {
val type = backingField.descriptor.type
assert(!KotlinBuiltIns.isPrimitiveType(type), { "'lateinit' modifier is not allowed on primitive types" })
val irBuilder = context.createIrBuilder(getter.symbol, getter.startOffset, getter.endOffset)
irBuilder.run {
getter.body = irBlockBody {
@@ -134,7 +113,7 @@ internal class LateinitLowering(
context.irBuiltIns.nothingType,
irNotEquals(irGet(resultVar), irNull()),
irReturn(irGet(resultVar)),
throwUninitializedPropertyAccessException(backingField.symbol)
throwUninitializedPropertyAccessException(backingField.name)
)
}
}
@@ -142,7 +121,7 @@ internal class LateinitLowering(
})
}
private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(backingFieldSymbol: IrSymbol) =
private fun IrBuilderWithScope.throwUninitializedPropertyAccessException(name: Name) =
irCall(throwErrorFunction, context.irBuiltIns.nothingType).apply {
if (generateParameterNameInAssertion) {
putValueArgument(
@@ -151,7 +130,7 @@ internal class LateinitLowering(
startOffset,
endOffset,
context.irBuiltIns.stringType,
backingFieldSymbol.descriptor.name.asString()
name.asString()
)
)
}
@@ -8,19 +8,20 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.irGetObject
import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.types.typeUtil.isUnit
internal class ReturnsInsertionLowering(val context: Context) : FileLoweringPass {
private val symbols = context.ir.symbols
override fun lower(irFile: IrFile) {
irFile.acceptVoid(object : IrElementVisitorVoid {
@@ -32,10 +33,10 @@ internal class ReturnsInsertionLowering(val context: Context) : FileLoweringPass
declaration.acceptChildrenVoid(this)
val body = declaration.body
if ((declaration.descriptor is ConstructorDescriptor || declaration.descriptor.returnType!!.isUnit()) && body != null) {
if ((declaration is IrConstructor || declaration.returnType.classifierOrNull == symbols.unit) && body != null) {
val irBuilder = context.createIrBuilder(declaration.symbol, declaration.startOffset, declaration.endOffset)
irBuilder.run {
(body as IrBlockBody).statements += irReturn(irGetObject(this@ReturnsInsertionLowering.context.ir.symbols.unit))
(body as IrBlockBody).statements += irReturn(irGetObject(symbols.unit))
}
}
}
@@ -1,127 +0,0 @@
/*
* Copyright 2010-2018 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 org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.visitors.*
import java.util.*
object CoroutineIntrinsicLambdaOrigin: IrStatementOriginImpl("Coroutine intrinsic lambda")
// TODO: Fix .parent for variables and use from common backend.
class SharedVariablesLowering(val context: BackendContext) : FunctionLoweringPass {
override fun lower(irFunction: IrFunction) {
SharedVariablesTransformer(irFunction).lowerSharedVariables()
}
private inner class SharedVariablesTransformer(val irFunction: IrFunction) {
val sharedVariables = mutableSetOf<IrVariable>()
fun lowerSharedVariables() {
collectSharedVariables()
if (sharedVariables.isEmpty()) return
rewriteSharedVariables()
}
private fun collectSharedVariables() {
irFunction.acceptVoid(object : IrElementVisitorVoid {
val relevantVars = mutableSetOf<IrVariable>()
val functionsVariables = mutableListOf<MutableSet<IrVariable>>()
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitFunction(declaration: IrFunction) {
functionsVariables.push(mutableSetOf())
declaration.acceptChildrenVoid(this)
functionsVariables.pop()
}
override fun visitContainerExpression(expression: IrContainerExpression) {
if (expression !is IrReturnableBlock || expression.origin != CoroutineIntrinsicLambdaOrigin)
super.visitContainerExpression(expression)
else {
functionsVariables.push(mutableSetOf())
expression.acceptChildrenVoid(this)
functionsVariables.pop()
}
}
override fun visitVariable(declaration: IrVariable) {
declaration.acceptChildrenVoid(this)
if (declaration.isVar) {
relevantVars.add(declaration)
functionsVariables.peek()!!.add(declaration)
}
}
override fun visitVariableAccess(expression: IrValueAccessExpression) {
expression.acceptChildrenVoid(this)
val value = expression.symbol.owner
//if (descriptor in relevantVars && descriptor.containingDeclaration != currentDeclaration) {
// TODO: fix lowerings to match check `(value as IrVariable).parent != currentDeclaration`
if (value in relevantVars && !functionsVariables.peek()!!.contains(value)) {
sharedVariables.add(value as IrVariable)
}
}
})
}
private fun rewriteSharedVariables() {
val transformedVariableSymbols = HashMap<IrValueSymbol, IrVariableSymbol>()
irFunction.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitVariable(declaration: IrVariable): IrStatement {
declaration.transformChildrenVoid(this)
if (declaration !in sharedVariables) return declaration
val newDeclaration = context.sharedVariablesManager.declareSharedVariable(declaration)
transformedVariableSymbols[declaration.symbol] = newDeclaration.symbol
return context.sharedVariablesManager.defineSharedValue(declaration, newDeclaration)
}
})
irFunction.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
expression.transformChildrenVoid(this)
val newSymbol = getTransformedSymbol(expression.symbol) ?: return expression
return context.sharedVariablesManager.getSharedValue(newSymbol, expression)
}
override fun visitSetVariable(expression: IrSetVariable): IrExpression {
expression.transformChildrenVoid(this)
val newDescriptor = getTransformedSymbol(expression.symbol) ?: return expression
return context.sharedVariablesManager.setSharedValue(newDescriptor, expression)
}
private fun getTransformedSymbol(oldSymbol: IrValueSymbol): IrVariableSymbol? =
transformedVariableSymbols.getOrElse(oldSymbol) {
assert(oldSymbol.owner !in sharedVariables) {
"Shared variable is not transformed: $oldSymbol"
}
null
}
})
}
}
}
@@ -5,47 +5,38 @@
package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.descriptors.replace
import org.jetbrains.kotlin.backend.common.ir.createFakeOverrideDescriptor
import org.jetbrains.kotlin.backend.common.lower.SimpleMemberScope
import org.jetbrains.kotlin.backend.common.lower.SymbolWithIrBuilder
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassConstructorDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedClassDescriptor
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.reportWarning
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.irasdescriptors.fqNameSafe
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWithStarProjections
import org.jetbrains.kotlin.backend.konan.irasdescriptors.typeWithoutArguments
import org.jetbrains.kotlin.backend.konan.SYNTHETIC_OFFSET
import org.jetbrains.kotlin.backend.konan.reportCompilationError
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
internal class TestProcessor (val context: KonanBackendContext) {
@@ -60,72 +51,65 @@ internal class TestProcessor (val context: KonanBackendContext) {
val IGNORE_FQ_NAME = FqName.fromSegments(listOf("kotlin", "test" , "Ignore"))
}
val symbols = context.ir.symbols
private val symbols = context.ir.symbols
val baseClassSuiteDescriptor = symbols.baseClassSuite.descriptor
private val baseClassSuite = symbols.baseClassSuite.owner
private val topLevelSuiteNames = mutableSetOf<String>()
// region Useful extensions.
var testSuiteCnt = 0
fun Name.synthesizeSuiteClassName() = identifier.synthesizeSuiteClassName()
fun String.synthesizeSuiteClassName() = "$this\$test\$${testSuiteCnt++}".synthesizedName
private var testSuiteCnt = 0
private fun Name.synthesizeSuiteClassName() = identifier.synthesizeSuiteClassName()
private fun String.synthesizeSuiteClassName() = "$this\$test\$${testSuiteCnt++}".synthesizedName
// IrFile always uses a forward slash as a directory separator.
private val IrFile.fileName
get() = name.substringAfterLast('/')
private val IrFile.topLevelSuiteName: String
get() {
val packageFqName = packageFragmentDescriptor.fqName
val packageFqName = fqName
val shortFileName = PackagePartClassUtils.getFilePartShortName(fileName)
return if (packageFqName.isRoot) shortFileName else "$packageFqName.$shortFileName"
}
private fun MutableList<TestFunction>.registerFunction(
function: IrFunctionSymbol,
function: IrFunction,
kinds: Collection<Pair<FunctionKind, /* ignored: */ Boolean>>) =
kinds.forEach { (kind, ignored) ->
add(TestFunction(function, kind, ignored))
}
private fun MutableList<TestFunction>.registerFunction(
function: IrFunctionSymbol,
function: IrFunction,
kind: FunctionKind,
ignored: Boolean
) = add(TestFunction(function, kind, ignored))
private fun <T: IrElement> IrStatementsBuilder<T>.generateFunctionRegistration(
receiver: IrValueDeclaration,
registerTestCase: IrFunctionSymbol,
registerFunction: IrFunctionSymbol,
registerTestCase: IrFunction,
registerFunction: IrFunction,
functions: Collection<TestFunction>) {
functions.forEach {
if (it.kind == FunctionKind.TEST) {
// Call registerTestCase(name: String, testFunction: () -> Unit) method.
+irCall(registerTestCase, registerTestCase.descriptor.returnType!!.toErasedIrType()).apply {
+irCall(registerTestCase).apply {
dispatchReceiver = irGet(receiver)
putValueArgument(0, IrConstImpl.string(
SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET,
context.irBuiltIns.stringType,
it.function.descriptor.name.identifier)
)
putValueArgument(0, irString(it.function.name.identifier))
putValueArgument(1, IrFunctionReferenceImpl(
SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET,
descriptor.valueParameters[1].type.toErasedIrType(),
it.function,
it.function.descriptor, 0))
putValueArgument(2, IrConstImpl.boolean(
SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET,
context.irBuiltIns.booleanType,
it.ignored
))
registerTestCase.valueParameters[1].type,
it.function.symbol,
it.function.descriptor,
typeArgumentsCount = 0,
valueArgumentsCount = 0))
putValueArgument(2, irBoolean(it.ignored))
}
} else {
// Call registerFunction(kind: TestFunctionKind, () -> Unit) method.
+irCall(registerFunction, registerFunction.descriptor.returnType!!.toErasedIrType()).apply {
+irCall(registerFunction).apply {
dispatchReceiver = irGet(receiver)
val testKindEntry = it.kind.runtimeKind
putValueArgument(0, IrGetEnumValueImpl(
@@ -134,12 +118,13 @@ internal class TestProcessor (val context: KonanBackendContext) {
symbols.testFunctionKind.typeWithoutArguments,
testKindEntry)
)
putValueArgument(1, IrFunctionReferenceImpl(
putValueArgument(1, IrFunctionReferenceImpl(SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET,
descriptor.valueParameters[1].type.toErasedIrType(),
it.function,
it.function.descriptor, 0))
registerFunction.valueParameters[1].type,
it.function.symbol,
it.function.descriptor,
typeArgumentsCount = 0,
valueArgumentsCount = 0))
}
}
}
@@ -149,7 +134,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
// region Classes for annotation collection.
internal enum class FunctionKind(annotationNameString: String, runtimeKindString: String) {
TEST("kotlin.test.Test", "") {
override val runtimeKindName: Name get() = throw NotImplementedError()
override val runtimeKindName: Name get() = throw NotImplementedError()
},
BEFORE_EACH("kotlin.test.BeforeEach", "BEFORE_EACH"),
@@ -169,34 +154,34 @@ internal class TestProcessor (val context: KonanBackendContext) {
private val FunctionKind.runtimeKind: IrEnumEntrySymbol
get() = symbols.getTestFunctionKind(this)
private fun IrType.isTestFunctionKind() = classifierOrNull == symbols.testFunctionKind
private data class TestFunction(
val function: IrFunctionSymbol,
val function: IrFunction,
val kind: FunctionKind,
val ignored: Boolean
)
private inner class TestClass(val ownerClass: IrClassSymbol) {
var companion: IrClassSymbol? = null
private inner class TestClass(val ownerClass: IrClass) {
var companion: IrClass? = null
val functions = mutableListOf<TestFunction>()
fun registerFunction(
function: IrFunctionSymbol,
function: IrFunction,
kinds: Collection<Pair<FunctionKind, /* ignored: */ Boolean>>
) = functions.registerFunction(function, kinds)
fun registerFunction(function: IrFunctionSymbol, kind: FunctionKind, ignored: Boolean) =
fun registerFunction(function: IrFunction, kind: FunctionKind, ignored: Boolean) =
functions.registerFunction(function, kind, ignored)
}
private inner class AnnotationCollector(val irFile: IrFile) : IrElementVisitorVoid {
val testClasses = mutableMapOf<IrClassSymbol, TestClass>()
val testClasses = mutableMapOf<IrClass, TestClass>()
val topLevelFunctions = mutableListOf<TestFunction>()
private fun MutableMap<IrClassSymbol, TestClass>.getTestClass(key: IrClassSymbol) =
private fun MutableMap<IrClass, TestClass>.getTestClass(key: IrClass) =
getOrPut(key) { TestClass(key) }
private fun MutableMap<IrClassSymbol, TestClass>.getTestClass(key: ClassDescriptor) =
getTestClass(symbols.symbolTable.referenceClass(key))
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
@@ -227,45 +212,50 @@ internal class TestProcessor (val context: KonanBackendContext) {
}
}
fun registerClassFunction(classDescriptor: ClassDescriptor,
function: IrFunctionSymbol,
fun registerClassFunction(irClass: IrClass,
function: IrFunction,
kinds: Collection<Pair<FunctionKind, /* ignored: */ Boolean>>) {
fun warn(msg: String) = context.reportWarning(msg, irFile, function.owner)
fun warn(msg: String) = context.reportWarning(msg, irFile, function)
kinds.forEach { (kind, ignored) ->
val annotation = kind.annotationFqName
when (kind) {
in FunctionKind.INSTANCE_KINDS -> with(classDescriptor) {
in FunctionKind.INSTANCE_KINDS -> with(irClass) {
when {
isInner ->
warn("Annotation $annotation is not allowed for methods of an inner class")
isAbstract() -> {
// We cannot create an abstract test class but it's allowed to mark its methods as
// tests because the class can be extended. So skip this case without warnings.
}
isCompanionObject ->
isCompanion ->
warn("Annotation $annotation is not allowed for methods of a companion object")
constructors.none { it.valueParameters.size == 0 } ->
warn("Test class has no default constructor: ${fqNameSafe}")
warn("Test class has no default constructor: $fqNameSafe")
else ->
testClasses.getTestClass(classDescriptor).registerFunction(function, kind, ignored)
testClasses.getTestClass(irClass).registerFunction(function, kind, ignored)
}
}
in FunctionKind.COMPANION_KINDS ->
when {
classDescriptor.isCompanionObject -> {
val containingClass = classDescriptor.containingDeclaration as ClassDescriptor
irClass.isCompanion -> {
val containingClass = irClass.parentAsClass
val testClass = testClasses.getTestClass(containingClass)
testClass.companion = symbols.symbolTable.referenceClass(classDescriptor)
testClass.companion = irClass
testClass.registerFunction(function, kind, ignored)
}
classDescriptor.kind == ClassKind.OBJECT -> {
testClasses.getTestClass(classDescriptor).registerFunction(function, kind, ignored)
irClass.kind == ClassKind.OBJECT -> {
testClasses.getTestClass(irClass).registerFunction(function, kind, ignored)
}
else -> warn("Annotation $annotation is only allowed for methods of an object " +
"(named or companion) or top level functions")
}
else -> throw IllegalStateException("Unreachable")
}
@@ -274,14 +264,14 @@ internal class TestProcessor (val context: KonanBackendContext) {
fun IrFunction.checkFunctionSignature() {
// Test runner requires test functions to have the following signature: () -> Unit.
if (descriptor.returnType != context.builtIns.unitType) {
if (!returnType.isUnit()) {
context.reportCompilationError(
"Test function must return Unit: ${descriptor.fqNameSafe}", irFile, this
"Test function must return Unit: $fqNameSafe", irFile, this
)
}
if (descriptor.valueParameters.isNotEmpty()) {
if (valueParameters.isNotEmpty()) {
context.reportCompilationError(
"Test function must have no arguments: ${descriptor.fqNameSafe}", irFile, this
"Test function must have no arguments: $fqNameSafe", irFile, this
)
}
}
@@ -314,7 +304,7 @@ internal class TestProcessor (val context: KonanBackendContext) {
// TODO: Use symbols instead of containingDeclaration when such information is available.
override fun visitFunction(declaration: IrFunction) {
val symbol = declaration.symbol
val owner = declaration.descriptor.containingDeclaration
val parent = declaration.parent
warnAboutLoneIgnore(symbol)
val kinds = FunctionKind.values().mapNotNull { kind ->
@@ -329,10 +319,10 @@ internal class TestProcessor (val context: KonanBackendContext) {
}
declaration.checkFunctionSignature()
when (owner) {
is PackageFragmentDescriptor -> topLevelFunctions.registerFunction(symbol, kinds)
is ClassDescriptor -> registerClassFunction(owner, symbol, kinds)
else -> UnsupportedOperationException("Cannot create test function $declaration (defined in $owner")
when (parent) {
is IrPackageFragment -> topLevelFunctions.registerFunction(declaration, kinds)
is IrClass -> registerClassFunction(parent, declaration, kinds)
else -> UnsupportedOperationException("Cannot create test function $declaration (defined in $parent")
}
}
}
@@ -340,60 +330,36 @@ internal class TestProcessor (val context: KonanBackendContext) {
//region Symbol and IR builders
/** Base class for getters (createInstance and getCompanion). */
private abstract inner class GetterBuilder(val returnType: IrType,
val testSuite: IrClassSymbol,
val getterName: Name)
: SymbolWithIrBuilder<IrSimpleFunctionSymbol, IrFunction>() {
val superFunction = baseClassSuiteDescriptor
.unsubstitutedMemberScope
.getContributedFunctions(getterName, NoLookupLocation.FROM_BACKEND)
.single { it.valueParameters.isEmpty() }
override fun doInitialize() {
val descriptor = symbol.descriptor as SimpleFunctionDescriptorImpl
descriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ testSuite.descriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ emptyList(),
/* returnType = */ returnType.toKotlinType(),
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PROTECTED
).apply {
overriddenDescriptors += superFunction
}
}
override fun buildSymbol() = IrSimpleFunctionSymbolImpl(
SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ testSuite.descriptor,
/* annotations = */ Annotations.EMPTY,
/* name = */ getterName,
/* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED,
/* source = */ SourceElement.NO_SOURCE
)
)
}
/**
* Builds a method in `[testSuite]` class with name `[getterName]`
* Builds a method in `[owner]` class with name `[getterName]`
* returning a reference to an object represented by `[objectSymbol]`.
*/
private inner class ObjectGetterBuilder(val objectSymbol: IrClassSymbol, testSuite: IrClassSymbol, getterName: Name)
: GetterBuilder(objectSymbol.typeWithoutArguments, testSuite, getterName) {
override fun buildIr(): IrFunction = IrFunctionImpl(
private fun buildObjectGetter(objectSymbol: IrClassSymbol,
owner: IrClass,
getterName: Name) = WrappedSimpleFunctionDescriptor().let { descriptor ->
IrFunctionImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
TEST_SUITE_GENERATED_MEMBER,
symbol,
this@ObjectGetterBuilder.returnType
IrSimpleFunctionSymbolImpl(descriptor),
getterName,
Visibilities.PROTECTED,
Modality.FINAL,
objectSymbol.typeWithStarProjections,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
).apply {
val builder = context.createIrBuilder(symbol)
createParameterDeclarations(context.ir.symbols.symbolTable)
body = builder.irBlockBody {
descriptor.bind(this)
parent = owner
val superFunction = baseClassSuite.simpleFunctions()
.single { it.name == getterName && it.valueParameters.isEmpty() }
createDispatchReceiverParameter()
overriddenSymbols += superFunction.symbol
body = context.createIrBuilder(symbol).irBlockBody {
+irReturn(IrGetObjectValueImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
objectSymbol.typeWithoutArguments, objectSymbol)
)
@@ -405,234 +371,202 @@ internal class TestProcessor (val context: KonanBackendContext) {
* Builds a method in `[testSuite]` class with name `[getterName]`
* returning a new instance of class referenced by [classSymbol].
*/
private inner class InstanceGetterBuilder(val classSymbol: IrClassSymbol, testSuite: IrClassSymbol, getterName: Name)
: GetterBuilder(classSymbol.typeWithStarProjections, testSuite, getterName) {
override fun buildIr() = IrFunctionImpl(
private fun buildInstanceGetter(classSymbol: IrClassSymbol,
owner: IrClass,
getterName: Name) = WrappedSimpleFunctionDescriptor().let { descriptor ->
IrFunctionImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
TEST_SUITE_GENERATED_MEMBER,
symbol,
this@InstanceGetterBuilder.returnType
IrSimpleFunctionSymbolImpl(descriptor),
getterName,
Visibilities.PROTECTED,
Modality.FINAL,
classSymbol.typeWithStarProjections,
isInline = false,
isExternal = false,
isTailrec = false,
isSuspend = false
).apply {
val builder = context.createIrBuilder(symbol)
createParameterDeclarations(context.ir.symbols.symbolTable)
body = builder.irBlockBody {
descriptor.bind(this)
parent = owner
val superFunction = baseClassSuite.simpleFunctions()
.single { it.name == getterName && it.valueParameters.isEmpty() }
createDispatchReceiverParameter()
overriddenSymbols += superFunction.symbol
body = context.createIrBuilder(symbol).irBlockBody {
val constructor = classSymbol.owner.constructors.single { it.valueParameters.isEmpty() }
+irReturn(irCall(constructor))
}
}
}
private val baseClassSuiteConstructor = baseClassSuite.constructors.single {
it.valueParameters.size == 2
&& it.valueParameters[0].type.isString() // name: String
&& it.valueParameters[1].type.isBoolean() // ignored: Boolean
}
/**
* Builds a constructor for a test suite class representing a test class (any class in the original IrFile with
* method(s) annotated with @Test). The test suite class is a subclass of ClassTestSuite<T>
* where T is the test class.
*/
private inner class ClassSuiteConstructorBuilder(val suiteName: String,
val testClassType: KotlinType,
val testCompanionType: KotlinType,
val testSuite: IrClassSymbol,
val functions: Collection<TestFunction>,
val ignored: Boolean)
: SymbolWithIrBuilder<IrConstructorSymbol, IrConstructor>() {
private fun IrClassSymbol.getFunction(name: String, predicate: (FunctionDescriptor) -> Boolean) =
symbols.symbolTable.referenceFunction(descriptor.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND)
.single(predicate))
override fun buildIr() = IrConstructorImpl(
private fun buildClassSuiteConstructor(suiteName: String,
testClassType: IrType,
testCompanionType: IrType,
testSuite: IrClassSymbol,
owner: IrClass,
functions: Collection<TestFunction>,
ignored: Boolean) = WrappedClassConstructorDescriptor().let { descriptor ->
IrConstructorImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
TEST_SUITE_GENERATED_MEMBER,
symbol,
testSuite.typeWithStarProjections
IrConstructorSymbolImpl(descriptor),
Name.special("<init>"),
Visibilities.PUBLIC,
testSuite.typeWithStarProjections,
isInline = false,
isExternal = false,
isPrimary = true
).apply {
descriptor.bind(this)
parent = owner
createParameterDeclarations(context.ir.symbols.symbolTable)
fun IrClass.getFunction(name: String, predicate: (IrSimpleFunction) -> Boolean) =
simpleFunctions().single { it.name.asString() == name && predicate(it) }
val registerTestCase = symbols.baseClassSuite.getFunction("registerTestCase") {
it.valueParameters.size == 3 &&
KotlinBuiltIns.isString(it.valueParameters[0].type) && // name: String
it.valueParameters[1].type.isFunctionType && // function: testClassType.() -> Unit
KotlinBuiltIns.isBoolean(it.valueParameters[2].type) // ignored: Boolean
val registerTestCase = baseClassSuite.getFunction("registerTestCase") {
it.valueParameters.size == 3
&& it.valueParameters[0].type.isString() // name: String
&& it.valueParameters[1].type.isFunction() // function: testClassType.() -> Unit
&& it.valueParameters[2].type.isBoolean() // ignored: Boolean
}
val registerFunction = symbols.baseClassSuite.getFunction("registerFunction") {
it.valueParameters.size == 2 &&
it.valueParameters[0].type == symbols.testFunctionKind.descriptor.defaultType && // kind: TestFunctionKind
it.valueParameters[1].type.isFunctionType // function: () -> Unit
val registerFunction = baseClassSuite.getFunction("registerFunction") {
it.valueParameters.size == 2
&& it.valueParameters[0].type.isTestFunctionKind() // kind: TestFunctionKind
&& it.valueParameters[1].type.isFunction() // function: () -> Unit
}
body = context.createIrBuilder(symbol).irBlockBody {
val superConstructor = symbols.baseClassSuiteConstructor
+IrDelegatingConstructorCallImpl(
startOffset = SYNTHETIC_OFFSET,
endOffset = SYNTHETIC_OFFSET,
type = context.irBuiltIns.unitType,
symbol = symbols.symbolTable.referenceConstructor(superConstructor),
descriptor = superConstructor,
typeArgumentsCount = 2
).apply {
putTypeArgument(0, testClassType.toErasedIrType())
putTypeArgument(1, testCompanionType.toErasedIrType())
+irDelegatingConstructorCall(baseClassSuiteConstructor).apply {
putTypeArgument(0, testClassType)
putTypeArgument(1, testCompanionType)
putValueArgument(0, IrConstImpl.string(
SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET,
context.irBuiltIns.stringType,
suiteName)
)
putValueArgument(1, IrConstImpl.boolean(
SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET,
context.irBuiltIns.booleanType,
ignored
))
putValueArgument(0, irString(suiteName))
putValueArgument(1, irBoolean(ignored))
}
generateFunctionRegistration(testSuite.owner.thisReceiver!!,
registerTestCase, registerFunction, functions)
}
}
override fun doInitialize() {
val descriptor = symbol.descriptor as ClassConstructorDescriptorImpl
descriptor.initialize(emptyList(), Visibilities.PUBLIC).apply {
returnType = testSuite.descriptor.defaultType
}
}
override fun buildSymbol() = IrConstructorSymbolImpl(
ClassConstructorDescriptorImpl.createSynthesized(
testSuite.descriptor,
Annotations.EMPTY,
true,
SourceElement.NO_SOURCE
)
)
}
private fun KotlinType.toErasedIrType(): IrType = context.ir.translateErased(this)
private val IrClass.ignored: Boolean get() = descriptor.annotations.hasAnnotation(IGNORE_FQ_NAME)
/**
* Builds a test suite class representing a test class (any class in the original IrFile with method(s)
* annotated with @Test). The test suite class is a subclass of ClassTestSuite<T> where T is the test class.
*/
private inner class ClassSuiteBuilder(testClass: IrClassSymbol,
testCompanion: IrClassSymbol?,
val containingDeclaration: DeclarationDescriptor,
val functions: Collection<TestFunction>)
: SymbolWithIrBuilder<IrClassSymbol, IrClass>() {
private val IrClassSymbol.ignored: Boolean get() = descriptor.annotations.hasAnnotation(IGNORE_FQ_NAME)
private val IrClassSymbol.isObject: Boolean get() = descriptor.kind == ClassKind.OBJECT
val suiteName = testClass.descriptor.fqNameSafe.toString()
val suiteClassName = testClass.descriptor.name.synthesizeSuiteClassName()
val testClassType = testClass.descriptor.defaultType
val testCompanionType = if (testClass.isObject) {
testClassType
} else {
testCompanion?.descriptor?.defaultType ?: context.irBuiltIns.nothing
}
val superType = baseClassSuiteDescriptor.defaultType.replace(listOf(testClassType, testCompanionType))
val constructorBuilder = ClassSuiteConstructorBuilder(
suiteName, testClassType, testCompanionType, symbol, functions, testClass.ignored
)
val instanceGetterBuilder: GetterBuilder
val companionGetterBuilder: GetterBuilder?
init {
if (testClass.isObject) {
instanceGetterBuilder = ObjectGetterBuilder(testClass, symbol, INSTANCE_GETTER_NAME)
companionGetterBuilder = ObjectGetterBuilder(testClass, symbol, COMPANION_GETTER_NAME)
} else {
instanceGetterBuilder = InstanceGetterBuilder(testClass, symbol, INSTANCE_GETTER_NAME)
companionGetterBuilder = testCompanion?.let {
ObjectGetterBuilder(it, symbol, COMPANION_GETTER_NAME)
}
}
}
override fun buildIr() = symbols.symbolTable.declareClass(
SYNTHETIC_OFFSET,
SYNTHETIC_OFFSET,
private fun buildClassSuite(testClass: IrClass,
testCompanion: IrClass?,
functions: Collection<TestFunction>) = WrappedClassDescriptor().let { descriptor ->
IrClassImpl(
SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
TEST_SUITE_CLASS,
symbol.descriptor).apply {
IrClassSymbolImpl(descriptor),
testClass.name.synthesizeSuiteClassName(),
ClassKind.CLASS,
Visibilities.PRIVATE,
Modality.FINAL,
isCompanion = false,
isInner = false,
isData = false,
isExternal = false,
isInline = false
).apply {
descriptor.bind(this)
createParameterDeclarations()
addMember(constructorBuilder.ir)
addMember(instanceGetterBuilder.ir)
companionGetterBuilder?.let { addMember(it.ir) }
addFakeOverrides(symbols.symbolTable)
setSuperSymbols(symbols.symbolTable)
}
override fun doInitialize() {
val descriptor = symbol.descriptor as ClassDescriptorImpl
val constructorDescriptor = constructorBuilder.symbol.descriptor
val testClassType = testClass.defaultType
val testCompanionType = if (testClass.kind == ClassKind.OBJECT) {
testClassType
} else {
testCompanion?.defaultType ?: context.irBuiltIns.nothingType
}
val contributedDescriptors = baseClassSuiteDescriptor
.unsubstitutedMemberScope
.getContributedDescriptors()
.map {
when {
it == instanceGetterBuilder.superFunction -> instanceGetterBuilder.symbol.descriptor
it == companionGetterBuilder?.superFunction -> companionGetterBuilder.symbol.descriptor
else -> it.createFakeOverrideDescriptor(symbol.descriptor as ClassDescriptorImpl)
}
}.filterNotNull()
descriptor.initialize(
SimpleMemberScope(contributedDescriptors),setOf(constructorDescriptor), constructorDescriptor
val constructor = buildClassSuiteConstructor(
testClass.fqNameSafe.toString(), testClassType, testCompanionType,
symbol, this, functions, testClass.ignored
)
constructorBuilder.initialize()
instanceGetterBuilder.initialize()
companionGetterBuilder?.initialize()
}
val instanceGetter: IrFunction
val companionGetter: IrFunction?
override fun buildSymbol() = symbols.symbolTable.referenceClass(
ClassDescriptorImpl(
/* containingDeclaration = */ containingDeclaration,
/* name = */ suiteClassName,
/* modality = */ Modality.FINAL,
/* kind = */ ClassKind.CLASS,
/* superTypes = */ listOf(superType),
/* source = */ SourceElement.NO_SOURCE,
/* isExternal = */ false,
/* storageManager = */ LockBasedStorageManager.NO_LOCKS
)
)
if (testClass.kind == ClassKind.OBJECT) {
instanceGetter = buildObjectGetter(testClass.symbol, this, INSTANCE_GETTER_NAME)
companionGetter = buildObjectGetter(testClass.symbol, this, COMPANION_GETTER_NAME)
} else {
instanceGetter = buildInstanceGetter(testClass.symbol, this, INSTANCE_GETTER_NAME)
companionGetter = testCompanion?.let {
buildObjectGetter(it.symbol, this, COMPANION_GETTER_NAME)
}
}
declarations += constructor
declarations += instanceGetter
companionGetter?.let { declarations += it }
superTypes += symbols.baseClassSuite.typeWith(listOf(testClassType, testCompanionType))
addFakeOverrides()
}
}
//endregion
// region IR generation methods
private fun generateClassSuite(irFile: IrFile, testClass: TestClass) =
with(ClassSuiteBuilder(testClass.ownerClass,
testClass.companion,
irFile.packageFragmentDescriptor,
testClass.functions)) {
initialize()
irFile.addChild(ir)
val irConstructor = ir.constructors.single()
irFile.addTopLevelInitializer(
IrCallImpl(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET, irConstructor.returnType, irConstructor.symbol),
context, threadLocal = true)
with(buildClassSuite(testClass.ownerClass, testClass.companion,testClass.functions)) {
irFile.addChild(this)
val irConstructor = constructors.single()
context.createIrBuilder(irFile.symbol).run {
irFile.addTopLevelInitializer(
irCall(irConstructor),
this@TestProcessor.context,
threadLocal = true)
}
}
/** Check if this fqName already used or not. */
private fun checkSuiteName(irFile: IrFile, name: String): Boolean {
if (topLevelSuiteNames.contains(name)) {
context.reportCompilationError("Package '${irFile.packageFragmentDescriptor.fqName}' has top-level test " +
context.reportCompilationError("Package '${irFile.fqName}' has top-level test " +
"functions in several files with the same name: '${irFile.fileName}'")
return false
}
topLevelSuiteNames.add(name)
return true
}
private val topLevelSuite = symbols.topLevelSuite.owner
private val topLevelSuiteConstructor = topLevelSuite.constructors.single {
it.valueParameters.size == 1
&& it.valueParameters[0].type.isString()
}
private val topLevelSuiteRegisterFunction = topLevelSuite.simpleFunctions().single {
it.name.asString() == "registerFunction"
&& it.valueParameters.size == 2
&& it.valueParameters[0].type.isTestFunctionKind()
&& it.valueParameters[1].type.isFunction()
}
private val topLevelSuiteRegisterTestCase = topLevelSuite.simpleFunctions().single {
it.name.asString() == "registerTestCase"
&& it.valueParameters.size == 3
&& it.valueParameters[0].type.isString()
&& it.valueParameters[1].type.isFunction()
&& it.valueParameters[2].type.isBoolean()
}
private fun generateTopLevelSuite(irFile: IrFile, functions: Collection<TestFunction>) {
val builder = context.createIrBuilder(irFile.symbol)
val suiteName = irFile.topLevelSuiteName
@@ -643,14 +577,14 @@ internal class TestProcessor (val context: KonanBackendContext) {
// TODO: an awful hack, we make this initializer thread local, so that it doesn't freeze suite,
// and later on we could modify some suite's properties. This shall be redesigned.
irFile.addTopLevelInitializer(builder.irBlock {
val constructorCall = irCall(symbols.topLevelSuiteConstructor).apply {
val constructorCall = irCall(topLevelSuiteConstructor).apply {
putValueArgument(0, IrConstImpl.string(SYNTHETIC_OFFSET, SYNTHETIC_OFFSET,
context.irBuiltIns.stringType, suiteName))
}
val testSuiteVal = irTemporary(constructorCall, "topLevelTestSuite")
generateFunctionRegistration(testSuiteVal,
symbols.topLevelSuiteRegisterTestCase,
symbols.topLevelSuiteRegisterFunction,
topLevelSuiteRegisterTestCase,
topLevelSuiteRegisterFunction,
functions)
}, context, threadLocal = true)
}
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedString
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.ir.IrElement
@@ -38,7 +39,6 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.util.OperatorNameConventions
class VarargInjectionLowering constructor(val context: CommonBackendContext): DeclarationContainerLoweringPass {
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.forEach{
@@ -99,63 +99,53 @@ class VarargInjectionLowering constructor(val context: CommonBackendContext): De
override fun visitVararg(expression: IrVararg): IrExpression {
expression.transformChildrenVoid(transformer)
val hasSpreadElement = hasSpreadElement(expression)
val irBuilder = context.createIrBuilder(owner, expression.startOffset, expression.endOffset)
irBuilder.run {
return irBuilder.irBlock(expression, null, expression.type) {
val type = expression.varargElementType
log { "$expression: array type:$type, is array of primitives ${!expression.type.isArray()}" }
val arrayHandle = arrayType(expression.type)
val block = irBlock(expression.type)
val vars = expression.elements.map {
val initVar = scope.createTemporaryVariable(
(it as? IrSpreadElement)?.expression ?: it as IrExpression,
"elem".synthesizedString, true)
block.statements.add(initVar)
it to initVar
it to irTemporaryVar(
(it as? IrSpreadElement)?.expression ?: it as IrExpression,
"elem".synthesizedString
)
}.toMap()
val arraySize = calculateArraySize(arrayHandle, hasSpreadElement, scope, expression, vars)
val array = arrayHandle.createArray(this, expression.varargElementType, arraySize)
val arrayTmpVariable = scope.createTemporaryVariable(array, "array".synthesizedString, true)
val indexTmpVariable = scope.createTemporaryVariable(kIntZero, "index".synthesizedString, true)
block.statements.add(arrayTmpVariable)
if (hasSpreadElement) {
block.statements.add(indexTmpVariable)
}
val arrayTmpVariable = irTemporaryVar(array, "array".synthesizedString)
lateinit var indexTmpVariable: IrVariable
if (hasSpreadElement)
indexTmpVariable = irTemporaryVar(kIntZero, "index".synthesizedString)
expression.elements.forEachIndexed { i, element ->
irBuilder.startOffset = element.startOffset
irBuilder.endOffset = element.endOffset
irBuilder.apply {
log { "element:$i> ${ir2string(element)}" }
val dst = vars[element]!!
if (element !is IrSpreadElement) {
val setArrayElementCall = irCall(arrayHandle.setMethodSymbol.owner)
setArrayElementCall.dispatchReceiver = irGet(arrayTmpVariable)
setArrayElementCall.putValueArgument(0, if (hasSpreadElement) irGet(indexTmpVariable) else irConstInt(i))
setArrayElementCall.putValueArgument(1, irGet(dst))
block.statements.add(setArrayElementCall)
if (hasSpreadElement) {
block.statements.add(incrementVariable(indexTmpVariable, kIntOne))
}
} else {
val arraySizeVariable = scope.createTemporaryVariable(irArraySize(arrayHandle, irGet(dst)), "length".synthesizedString)
block.statements.add(arraySizeVariable)
val copyCall = irCall(arrayHandle.copyRangeToSymbol.owner).apply {
extensionReceiver = irGet(dst)
putValueArgument(0, irGet(arrayTmpVariable)) /* destination */
putValueArgument(1, kIntZero) /* fromIndex */
putValueArgument(2, irGet(arraySizeVariable)) /* toIndex */
putValueArgument(3, irGet(indexTmpVariable)) /* destinationIndex */
}
block.statements.add(copyCall)
block.statements.add(incrementVariable(indexTmpVariable, irGet(arraySizeVariable)))
log { "element:$i:spread element> ${ir2string(element.expression)}" }
irBuilder.at(element.startOffset, element.endOffset)
log { "element:$i> ${ir2string(element)}" }
val dst = vars[element]!!
if (element !is IrSpreadElement) {
+irCall(arrayHandle.setMethodSymbol.owner).apply {
dispatchReceiver = irGet(arrayTmpVariable)
putValueArgument(0, if (hasSpreadElement) irGet(indexTmpVariable) else irConstInt(i))
putValueArgument(1, irGet(dst))
}
if (hasSpreadElement)
+incrementVariable(indexTmpVariable, kIntOne)
} else {
val arraySizeVariable = irTemporary(irArraySize(arrayHandle, irGet(dst)), "length".synthesizedString)
+irCall(arrayHandle.copyRangeToSymbol.owner).apply {
extensionReceiver = irGet(dst)
putValueArgument(0, irGet(arrayTmpVariable)) /* destination */
putValueArgument(1, kIntZero) /* fromIndex */
putValueArgument(2, irGet(arraySizeVariable)) /* toIndex */
putValueArgument(3, irGet(indexTmpVariable)) /* destinationIndex */
}
+incrementVariable(indexTmpVariable, irGet(arraySizeVariable))
log { "element:$i:spread element> ${ir2string(element.expression)}" }
}
}
block.statements.add(irGet(arrayTmpVariable))
return block
+irGet(arrayTmpVariable)
}
}
})
@@ -273,6 +263,5 @@ class VarargInjectionLowering constructor(val context: CommonBackendContext): De
private fun IrBuilderWithScope.irConstInt(value: Int): IrConst<Int> =
IrConstImpl.int(startOffset, endOffset, context.irBuiltIns.intType, value)
private fun IrBuilderWithScope.irBlock(type: IrType): IrBlock = IrBlockImpl(startOffset, endOffset, type)
private val IrBuilderWithScope.kIntZero get() = irConstInt(0)
private val IrBuilderWithScope.kIntOne get() = irConstInt(1)
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.isSimpleTypeWithQuestionMark
@@ -37,7 +37,7 @@ internal class BackingFieldVisitor(val context: Context) : IrElementVisitorVoid
override fun visitClass(declaration: IrClass) {
if (declaration.isInner)
declaration.addChild(context.specialDeclarationsFactory.getOuterThisField(declaration))
declaration.declarations += context.specialDeclarationsFactory.getOuterThisField(declaration)
// Mark all dangling fields (they are created when class is inherited via delegation).
declaration.declarations.filterIsInstance<IrField>().forEach {
@@ -6,22 +6,21 @@
package org.jetbrains.kotlin.ir.util
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.descriptors.substitute
import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.backend.konan.KonanCompilationException
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
@@ -30,14 +29,15 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.OverridingStrategy
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.calls.checkers.isRestrictsSuspensionReceiver
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.KotlinType
@@ -50,38 +50,29 @@ internal fun IrExpression.isNullConst() = this is IrConst<*> && this.kind == IrC
private var topLevelInitializersCounter = 0
internal fun IrFile.addTopLevelInitializer(expression: IrExpression, context: KonanBackendContext, threadLocal: Boolean) {
val fieldDescriptor = PropertyDescriptorImpl.create(
this.packageFragmentDescriptor,
val descriptor = WrappedFieldDescriptor(
if (threadLocal)
Annotations.create(listOf(AnnotationDescriptorImpl(context.ir.symbols.threadLocal.defaultType,
emptyMap(), SourceElement.NO_SOURCE)))
else
Annotations.EMPTY,
Modality.FINAL,
Visibilities.PRIVATE,
false,
"topLevelInitializer${topLevelInitializersCounter++}".synthesizedName,
CallableMemberDescriptor.Kind.DECLARATION,
SourceElement.NO_SOURCE,
false,
false,
false,
false,
false,
false
Annotations.EMPTY
)
fieldDescriptor.setType(expression.type.toKotlinType(), emptyList(), null, null)
fieldDescriptor.initialize(null, null)
val irField = IrFieldImpl(
expression.startOffset, expression.endOffset,
IrDeclarationOrigin.DEFINED, fieldDescriptor, expression.type
)
IrDeclarationOrigin.DEFINED,
IrFieldSymbolImpl(descriptor),
"topLevelInitializer${topLevelInitializersCounter++}".synthesizedName,
expression.type,
Visibilities.PRIVATE,
isFinal = true,
isExternal = false,
isStatic = true
).apply {
descriptor.bind(this)
irField.initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, expression)
this.addChild(irField)
initializer = IrExpressionBodyImpl(expression.startOffset, expression.endOffset, expression)
}
addChild(irField)
}
fun IrClass.addFakeOverrides(symbolTable: SymbolTable) {
@@ -155,72 +146,6 @@ fun IrFunction.createParameterDeclarations(symbolTable: SymbolTable) {
}
}
private fun createFakeOverride(
descriptor: CallableMemberDescriptor,
overriddenDeclarations: List<IrDeclaration>,
irClass: IrClass
): IrDeclaration {
// TODO: this function doesn't substitute types.
fun IrSimpleFunction.copyFake(descriptor: FunctionDescriptor): IrSimpleFunction = IrFunctionImpl(
irClass.startOffset, irClass.endOffset, IrDeclarationOrigin.FAKE_OVERRIDE, descriptor, returnType
).also {
it.parent = irClass
it.createDispatchReceiverParameter()
it.extensionReceiverParameter = this.extensionReceiverParameter?.let {
IrValueParameterImpl(
it.startOffset,
it.endOffset,
IrDeclarationOrigin.DEFINED,
it.descriptor.extensionReceiverParameter!!,
it.type,
null
)
}
this.valueParameters.mapTo(it.valueParameters) { oldParameter ->
IrValueParameterImpl(
oldParameter.startOffset,
oldParameter.endOffset,
IrDeclarationOrigin.DEFINED,
it.descriptor.valueParameters[oldParameter.index],
oldParameter.type,
(oldParameter as? IrValueParameter)?.varargElementType
)
}
this.typeParameters.mapTo(it.typeParameters) { oldParameter ->
IrTypeParameterImpl(
irClass.startOffset,
irClass.endOffset,
IrDeclarationOrigin.DEFINED,
it.descriptor.typeParameters[oldParameter.index]
).apply {
superTypes += oldParameter.superTypes
}
}
}
val copiedDeclaration = overriddenDeclarations.first()
return when (copiedDeclaration) {
is IrSimpleFunction -> copiedDeclaration.copyFake(descriptor as FunctionDescriptor)
is IrProperty -> IrPropertyImpl(
irClass.startOffset,
irClass.endOffset,
IrDeclarationOrigin.FAKE_OVERRIDE,
descriptor as PropertyDescriptor
).apply {
parent = irClass
getter = copiedDeclaration.getter?.copyFake(descriptor.getter!!)
setter = copiedDeclaration.setter?.copyFake(descriptor.setter!!)
}
else -> error(copiedDeclaration)
}
}
fun IrSimpleFunction.setOverrides(symbolTable: ReferenceSymbolTable) {
assert(this.overriddenSymbols.isEmpty())
@@ -229,44 +154,6 @@ fun IrSimpleFunction.setOverrides(symbolTable: ReferenceSymbolTable) {
}
}
fun IrClass.simpleFunctions(): List<IrSimpleFunction> = this.declarations.flatMap {
when (it) {
is IrSimpleFunction -> listOf(it)
is IrProperty -> listOfNotNull(it.getter, it.setter)
else -> emptyList()
}
}
fun IrClass.createParameterDeclarations() {
thisReceiver = IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.INSTANCE_RECEIVER,
descriptor.thisAsReceiverParameter,
this.symbol.typeWith(this.typeParameters.map { it.defaultType }),
null
).also { valueParameter ->
valueParameter.parent = this
}
assert(typeParameters.isEmpty())
assert(descriptor.declaredTypeParameters.isEmpty())
}
fun IrFunction.createDispatchReceiverParameter() {
assert(this.dispatchReceiverParameter == null)
val descriptor = this.descriptor.dispatchReceiverParameter ?: return
this.dispatchReceiverParameter = IrValueParameterImpl(
startOffset,
endOffset,
IrDeclarationOrigin.DEFINED,
descriptor,
(parent as IrClass).defaultType,
null
).also { it.parent = this }
}
fun IrClass.createParameterDeclarations(symbolTable: SymbolTable) {
this.descriptor.declaredTypeParameters.mapTo(this.typeParameters) {
IrTypeParameterImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, it).apply {
@@ -283,29 +170,6 @@ fun IrClass.createParameterDeclarations(symbolTable: SymbolTable) {
)
}
fun IrClass.setSuperSymbols(superTypes: List<IrType>) {
val supers = superTypes.map { it.getClass()!! }
assert(this.superDescriptors().toSet() == supers.map { it.descriptor }.toSet())
assert(this.superTypes.isEmpty())
this.superTypes += superTypes
val superMembers = supers.flatMap {
it.simpleFunctions()
}.associateBy { it.descriptor }
this.simpleFunctions().forEach {
assert(it.overriddenSymbols.isEmpty())
it.descriptor.overriddenDescriptors.mapTo(it.overriddenSymbols) {
val superMember = superMembers[it.original] ?: error(it.original)
superMember.symbol
}
}
}
private fun IrClass.superDescriptors() =
this.descriptor.typeConstructor.supertypes.map { it.constructor.declarationDescriptor as ClassDescriptor }
fun IrClass.setSuperSymbols(symbolTable: ReferenceSymbolTable) {
assert(this.superTypes.isEmpty())
this.descriptor.typeConstructor.supertypes.mapTo(this.superTypes) { symbolTable.translateErased(it) }
@@ -315,52 +179,110 @@ fun IrClass.setSuperSymbols(symbolTable: ReferenceSymbolTable) {
}
}
fun IrClass.setSuperSymbolsAndAddFakeOverrides(superTypes: List<IrType>) {
val overriddenSuperMembers = this.declarations.map { it.descriptor }
.filterIsInstance<CallableMemberDescriptor>().flatMap { it.overriddenDescriptors.map { it.original } }.toSet()
fun IrClass.simpleFunctions() = declarations.flatMap {
when (it) {
is IrSimpleFunction -> listOf(it)
is IrProperty -> listOfNotNull(it.getter, it.setter)
else -> emptyList()
}
}
val unoverriddenSuperMembers = superTypes.map { it.getClass()!! }.flatMap {
it.declarations.filter { it.descriptor !in overriddenSuperMembers }.mapNotNull {
when (it) {
is IrSimpleFunction -> it.descriptor to it
is IrProperty -> it.descriptor to it
else -> null
fun IrClass.createParameterDeclarations() {
assert (thisReceiver == null)
thisReceiver = WrappedReceiverParameterDescriptor().let {
IrValueParameterImpl(
startOffset, endOffset,
IrDeclarationOrigin.INSTANCE_RECEIVER,
IrValueParameterSymbolImpl(it),
Name.special("<this>"),
0,
symbol.typeWith(typeParameters.map { it.defaultType }),
null,
false,
false
).apply {
it.bind(this)
parent = this@createParameterDeclarations
}
}
}
fun IrFunction.createDispatchReceiverParameter(origin: IrDeclarationOrigin? = null) {
assert(dispatchReceiverParameter == null)
dispatchReceiverParameter = WrappedReceiverParameterDescriptor().let {
IrValueParameterImpl(
startOffset, endOffset,
origin ?: parentAsClass.origin,
IrValueParameterSymbolImpl(it),
Name.special("<this>"),
0,
parentAsClass.defaultType,
null,
false,
false
).apply {
it.bind(this)
parent = this@createDispatchReceiverParameter
}
}
}
fun IrClass.addFakeOverrides() {
fun IrDeclaration.toList() = when (this) {
is IrSimpleFunction -> listOf(this)
is IrProperty -> listOfNotNull(getter, setter)
else -> emptyList()
}
val overriddenFunctions = declarations
.flatMap { it.toList() }
.flatMap { it.overriddenSymbols.map { it.owner } }
.toSet()
val unoverriddenSuperFunctions = superTypes
.map { it.getClass()!! }
.flatMap { irClass ->
irClass.declarations
.flatMap { it.toList() }
.filter { it !in overriddenFunctions }
}
}
}.toMap()
.toMutableSet()
val irClass = this
// TODO: A dirty hack.
val groupedUnoverriddenSuperFunctions = unoverriddenSuperFunctions.groupBy { it.name.asString() + it.allParameters.size }
val overridingStrategy = object : OverridingStrategy() {
override fun addFakeOverride(fakeOverride: CallableMemberDescriptor) {
val overriddenDeclarations =
fakeOverride.overriddenDescriptors.map { unoverriddenSuperMembers[it]!! }
fun createFakeOverride(overriddenFunctions: List<IrSimpleFunction>) =
overriddenFunctions.first().let { irFunction ->
val descriptor = WrappedSimpleFunctionDescriptor()
IrFunctionImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
IrDeclarationOrigin.FAKE_OVERRIDE,
IrSimpleFunctionSymbolImpl(descriptor),
irFunction.name,
Visibilities.INHERITED,
Modality.OPEN,
irFunction.returnType,
irFunction.isInline,
irFunction.isExternal,
irFunction.isTailrec,
irFunction.isSuspend
).apply {
descriptor.bind(this)
parent = this@addFakeOverrides
overriddenSymbols += overriddenFunctions.map { it.symbol }
copyParameterDeclarationsFrom(irFunction)
}
}
assert(overriddenDeclarations.isNotEmpty())
val fakeOverriddenFunctions = groupedUnoverriddenSuperFunctions
.asSequence()
.associate { it.value.first() to createFakeOverride(it.value) }
.toMutableMap()
irClass.declarations.add(createFakeOverride(fakeOverride, overriddenDeclarations, irClass))
}
override fun inheritanceConflict(first: CallableMemberDescriptor, second: CallableMemberDescriptor) {
error("inheritance conflict in synthesized class ${irClass.descriptor}:\n $first\n $second")
}
override fun overrideConflict(fromSuper: CallableMemberDescriptor, fromCurrent: CallableMemberDescriptor) {
error("override conflict in synthesized class ${irClass.descriptor}:\n $fromSuper\n $fromCurrent")
}
}
unoverriddenSuperMembers.keys.groupBy { it.name }.forEach { (name, members) ->
OverridingUtil.generateOverridesInFunctionGroup(
name,
members,
emptyList(),
this.descriptor,
overridingStrategy
)
}
this.setSuperSymbols(superTypes)
declarations += fakeOverriddenFunctions.values
}
private fun IrElement.innerStartOffset(descriptor: DeclarationDescriptorWithSource): Int =
@@ -389,6 +311,11 @@ fun IrDeclarationContainer.addChild(declaration: IrDeclaration) {
declaration.accept(SetDeclarationsParentVisitor, this)
}
fun <T: IrElement> T.setDeclarationsParent(parent: IrDeclarationParent): T {
accept(SetDeclarationsParentVisitor, parent)
return this
}
object SetDeclarationsParentVisitor : IrElementVisitor<Unit, IrDeclarationParent> {
override fun visitElement(element: IrElement, data: IrDeclarationParent) {
if (element !is IrDeclarationParent) {
@@ -612,25 +539,6 @@ fun IrMemberAccessExpression.getArgumentsWithIr(): List<Pair<IrValueParameter, I
return res
}
fun CallableMemberDescriptor.createValueParameter(
index: Int,
name: String,
type: IrType,
startOffset: Int,
endOffset: Int
): IrValueParameter {
val descriptor = ValueParameterDescriptorImpl(
this, null,
index,
Annotations.EMPTY,
Name.identifier(name),
type.toKotlinType(),
false, false, false, null, SourceElement.NO_SOURCE
)
return IrValueParameterImpl(startOffset, endOffset, IrDeclarationOrigin.DEFINED, descriptor, type, null)
}
fun ReferenceSymbolTable.translateErased(type: KotlinType): IrSimpleType {
val descriptor = TypeUtils.getClassDescriptor(type)
if (descriptor == null) return translateErased(type.immediateSupertypes().first())
@@ -643,9 +551,9 @@ fun ReferenceSymbolTable.translateErased(type: KotlinType): IrSimpleType {
}
fun CommonBackendContext.createArrayOfExpression(
startOffset: Int, endOffset: Int,
arrayElementType: IrType,
arrayElements: List<IrExpression>,
startOffset: Int, endOffset: Int
arrayElements: List<IrExpression>
): IrExpression {
val arrayType = ir.symbols.array.typeWith(arrayElementType)
@@ -659,34 +567,27 @@ fun CommonBackendContext.createArrayOfExpression(
fun createField(
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
type: IrType,
name: Name,
isMutable: Boolean,
origin: IrDeclarationOrigin,
owner: ClassDescriptor
): IrField {
val descriptor = PropertyDescriptorImpl.create(
/* containingDeclaration = */ owner,
/* annotations = */ Annotations.EMPTY,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE,
/* isVar = */ isMutable,
/* name = */ name,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE,
/* lateInit = */ false,
/* isConst = */ false,
/* isExpect = */ false,
/* isActual = */ false,
/* isExternal = */ false,
/* isDelegated = */ false
owner: IrClass
) = WrappedFieldDescriptor().let {
IrFieldImpl(
startOffset, endOffset,
origin,
IrFieldSymbolImpl(it),
name,
type,
Visibilities.PRIVATE,
!isMutable,
false,
false
).apply {
initialize(null, null)
setType(type.toKotlinType(), emptyList(), owner.thisAsReceiverParameter, null)
it.bind(this)
owner.declarations += this
parent = owner
}
return IrFieldImpl(startOffset, endOffset, origin, descriptor, type)
}
fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter {
@@ -710,16 +611,5 @@ val IrType.isSimpleTypeWithQuestionMark: Boolean
fun IrClass.defaultOrNullableType(hasQuestionMark: Boolean) =
if (hasQuestionMark) this.defaultType.makeNullable() else this.defaultType
fun FunctionDescriptor.createOverriddenDescriptor(owner: ClassDescriptor, final: Boolean = true): FunctionDescriptor {
return this.newCopyBuilder()
.setOwner(owner)
.setCopyOverrides(true)
.setModality(if (final) Modality.FINAL else Modality.OPEN)
.setDispatchReceiverParameter(owner.thisAsReceiverParameter)
.build()!!.apply {
overriddenDescriptors = listOf(this@createOverriddenDescriptor)
}
}
fun IrFunction.isRestrictedSuspendFunction(languageVersionSettings: LanguageVersionSettings): Boolean =
this.descriptor.extensionReceiverParameter?.type?.isRestrictsSuspensionReceiver(languageVersionSettings) == true